diff --git a/AndroidKernel.mk b/AndroidKernel.mk index beefecad0ab03b0df9cd870391f215d24618cbde..9931150b2b9a00df72e667d6ae34354ac2036cb5 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -100,7 +100,10 @@ endif KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr KERNEL_MODULES_INSTALL ?= system KERNEL_MODULES_OUT ?= $(PRODUCT_OUT)/$(KERNEL_MODULES_INSTALL)/lib/modules - +ifneq ($(SOMC_PLATFORM),) +KERNEL_DIFFCONFIG ?= $(TARGET_PRODUCT)_diffconfig +endif +KERNEL_SRC_DIR := $(TARGET_KERNEL_SOURCE) TARGET_PREBUILT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL) define mv-modules @@ -119,6 +122,7 @@ mpath=`dirname $$mdpath`; rm -rf $$mpath;\ fi endef +FORCE: ifneq ($(KERNEL_LEGACY_DIR),true) $(KERNEL_USR): $(KERNEL_HEADERS_INSTALL) rm -rf $(KERNEL_SYMLINK) @@ -130,12 +134,9 @@ endif $(KERNEL_OUT): mkdir -p $(KERNEL_OUT) -$(KERNEL_CONFIG): $(KERNEL_OUT) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) - $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ - echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ - echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi +$(KERNEL_CONFIG): $(KERNEL_OUT) FORCE + env KBUILD_DIFFCONFIG=$(KERNEL_DIFFCONFIG) \ + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) $(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) $(hide) echo "Building kernel..." @@ -149,12 +150,14 @@ $(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \ rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \ + env KBUILD_DIFFCONFIG=$(KERNEL_DIFFCONFIG) \ + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install; fi $(hide) if [ "$(KERNEL_HEADER_DEFCONFIG)" != "$(KERNEL_DEFCONFIG)" ]; then \ echo "Used a different defconfig for header generation"; \ rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi + env KBUILD_DIFFCONFIG=$(KERNEL_DIFFCONFIG) \ + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ @@ -162,13 +165,33 @@ $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG) $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags + @if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ + echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ + echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; \ + fi + +platformconfig: KERNEL_DIFFCONFIG="" +platformconfig: kernelconfig kernelconfig: $(KERNEL_OUT) $(KERNEL_CONFIG) - env KCONFIG_NOTIMESTAMP=true \ + @env KCONFIG_NOTIMESTAMP=true \ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig - env KCONFIG_NOTIMESTAMP=true \ + @env KCONFIG_NOTIMESTAMP=true \ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig - cp $(KERNEL_OUT)/defconfig $(TARGET_KERNEL_SOURCE)/arch/$(KERNEL_ARCH)/configs/$(KERNEL_DEFCONFIG) + @env KCONFIG_NOTIMESTAMP=true KBUILD_DIFFCONFIG=$(KERNEL_DIFFCONFIG) \ + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savediffconfig + @if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ + echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ + echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ + $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; \ + fi + @if [ ! $(KERNEL_DIFFCONFIG) ]; then \ + cp -f $(KERNEL_OUT)/defconfig $(KERNEL_SRC_DIR)/arch/$(KERNEL_ARCH)/configs/$(KERNEL_DEFCONFIG); \ + echo ===========; \ + echo $(KERNEL_DEFCONFIG) has been modified !; \ + echo ===========; \ + fi endif endif diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt index 5bda5031c83de2b6e85ff2a6fe8bb3a8107a4aa5..d88f0c70cd7fc470875960d07a63fb883e75d48b 100644 --- a/Documentation/blockdev/zram.txt +++ b/Documentation/blockdev/zram.txt @@ -59,27 +59,16 @@ num_devices parameter is optional and tells zram how many devices should be pre-created. Default: 1. 2) Set max number of compression streams - Compression backend may use up to max_comp_streams compression streams, - thus allowing up to max_comp_streams concurrent compression operations. - By default, compression backend uses single compression stream. - - Examples: - #show max compression streams number + Regardless the value passed to this attribute, ZRAM will always + allocate multiple compression streams - one per online CPUs - thus + allowing several concurrent compression operations. The number of + allocated compression streams goes down when some of the CPUs + become offline. There is no single-compression-stream mode anymore, + unless you are running a UP system or has only 1 CPU online. + + To find out how many streams are currently available: cat /sys/block/zram0/max_comp_streams - #set max compression streams number to 3 - echo 3 > /sys/block/zram0/max_comp_streams - -Note: -In order to enable compression backend's multi stream support max_comp_streams -must be initially set to desired concurrency level before ZRAM device -initialisation. Once the device initialised as a single stream compression -backend (max_comp_streams equals to 1), you will see error if you try to change -the value of max_comp_streams because single stream compression backend -implemented as a special case by lock overhead issue and does not support -dynamic max_comp_streams. Only multi stream backend supports dynamic -max_comp_streams adjustment. - 3) Select compression algorithm Using comp_algorithm device attribute one can see available and currently selected (shown in square brackets) compression algorithms, diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt index 440628d02630740cbac0a96dc97ed171b50dce39..2989fbfe7972a56bf69539e79c30a5c0a757b942 100644 --- a/Documentation/devicetree/bindings/arm/msm/imem.txt +++ b/Documentation/devicetree/bindings/arm/msm/imem.txt @@ -73,11 +73,6 @@ USB Diag Cookies: Memory region used to store USB PID and serial numbers to be used by bootloader in download mode. -SSR Minidump Offset -------------------- --Compatible: "qcom,msm-imem-minidump" --reg: start address and size of ssr imem region - Required properties: -compatible: "qcom,msm-imem-diag-dload" -reg: start address and size of USB Diag download mode region in imem @@ -126,9 +121,4 @@ Example: compatible = "qcom,msm-imem-emergency_download_mode"; reg = <0xfe0 12>; }; - - ss_mdump@b88 { - compatible = "qcom,msm-imem-minidump"; - reg = <0xb88 28>; - }; }; diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index c264f9f65265232a69addff7c7e0f69c91aca77c..d442cf02a816fcaf2360b579aa09ab101365df0d 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -86,9 +86,6 @@ SoCs: - MSM8998 compatible = "qcom,msm8998" -- MSM8998_9x55 - compatible = "qcom,msm8998-9x55" - - MSMHAMSTER compatible = "qcom,msmhamster" @@ -110,12 +107,6 @@ SoCs: - SDA630 compatible = "qcom,sda630" -- SDM636 - compatible = "qcom,sdm636" - -- SDA636 - compatible = "qcom,sda636" - - MSM8952 compatible = "qcom,msm8952" @@ -175,9 +166,6 @@ Generic board variants: - RUMI device: compatible = "qcom,rumi" -- SVR device: - compatible = "qcom,svr" - Boards (SoC type + board variant): @@ -211,7 +199,6 @@ compatible = "qcom,apqtitanium-mtp" compatible = "qcom,apq8098-cdp" compatible = "qcom,apq8098-mtp" compatible = "qcom,apq8098-qrd" -compatible = "qcom,apq8098-svr" compatible = "qcom,mdm9630-cdp" compatible = "qcom,mdm9630-mtp" compatible = "qcom,mdm9630-sim" @@ -283,8 +270,6 @@ compatible = "qcom,msm8998-rumi" compatible = "qcom,msm8998-cdp" compatible = "qcom,msm8998-mtp" compatible = "qcom,msm8998-qrd" -compatible = "qcom,msm8998-9x55-cdp" -compatible = "qcom,msm8998-9x55-mtp" compatible = "qcom,msmhamster-rumi" compatible = "qcom,msmhamster-cdp" compatible = "qcom,msmhamster-mtp" @@ -301,12 +286,6 @@ compatible = "qcom,sda658-mtp" compatible = "qcom,sda658-cdp" compatible = "qcom,sda660-mtp" compatible = "qcom,sda660-cdp" -compatible = "qcom,sdm636-cdp" -compatible = "qcom,sdm636-mtp" -compatible = "qcom,sdm636-qrd" -compatible = "qcom,sda636-qrd" -compatible = "qcom,sda636-mtp" -compatible = "qcom,sda636-cdp" compatible = "qcom,sdm630-rumi" compatible = "qcom,sdm630-mtp" compatible = "qcom,sdm630-cdp" diff --git a/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt index 1114308f9436dc730357a86f76694a3077e68a73..ce2d8bd54e43ed917075d8a6c02905a741ba9453 100644 --- a/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt +++ b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt @@ -2,15 +2,12 @@ Qualcomm Technologies, Inc. Remote Debugger (RDBG) driver Required properties: -compatible : Should be one of - To communicate with adsp + To communicate with modem qcom,smp2pgpio_client_rdbg_2_in (inbound) qcom,smp2pgpio_client_rdbg_2_out (outbound) To communicate with modem qcom,smp2pgpio_client_rdbg_1_in (inbound) qcom,smp2pgpio_client_rdbg_1_out (outbound) - To communicate with cdsp - qcom,smp2pgpio_client_rdbg_5_in (inbound) - qcom,smp2pgpio_client_rdbg_5_out (outbound) -gpios : the relevant gpio pins of the entry. Example: diff --git a/Documentation/devicetree/bindings/cnss/cnss-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt index 6aa3bfe4b1d8f3568141bd5dd09667d86615e440..6d63d1123f4c06e94ef058724e0522099d82f7ef 100644 --- a/Documentation/devicetree/bindings/cnss/cnss-wlan.txt +++ b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt @@ -11,9 +11,8 @@ the WLAN enable GPIO, 3.3V fixed voltage regulator resources. It also provides the reserved RAM dump memory location and size. Required properties: - - compatible: "qcom,cnss" for QCA6174 device - "qcom,cnss-qca6290" for QCA6290 device - - wlan-en-gpio: WLAN_EN GPIO signal specified by the chip specifications + - compatible: "qcom,cnss" + - wlan-en-gpio: WLAN_EN GPIO signal specified by QCA6174 specifications - vdd-wlan-supply: phandle to the regulator device tree node - pinctrl-names: Names corresponding to the numbered pinctrl states - pinctrl-: Pinctrl states as described in @@ -45,13 +44,6 @@ Optional properties: which should be drived depending on platforms - qcom,is-dual-wifi-enabled: Boolean property to control wlan enable(wlan-en) gpio on dual-wifi platforms. - - vdd-wlan-en-supply: WLAN_EN fixed regulator specified by QCA6174 specifications. - - qcom,wlan-en-vreg-support: Boolean property to decide the whether the WLAN_EN pin - is a gpio or fixed regulator. - - qcom,mhi: phandle to indicate the device which needs MHI support. - - qcom,cap-tsf-gpio: WLAN_TSF_CAPTURED GPIO signal specified by the chip - specifications, should be drived depending on - products Example: @@ -68,6 +60,4 @@ Example: pinctrl-0 = <&cnss_default>; qcom,wlan-rc-num = <0>; qcom,wlan-smmu-iova-address = <0 0x10000000>; - qcom,mhi = <&mhi_wlan>; - qcom,cap-tsf-gpio = <&tlmm 126 1>; }; diff --git a/Documentation/devicetree/bindings/debug_memory/debug_memory.txt b/Documentation/devicetree/bindings/debug_memory/debug_memory.txt new file mode 100644 index 0000000000000000000000000000000000000000..e7db6efd11c1262e70a548c69b814c1f092eadb4 --- /dev/null +++ b/Documentation/devicetree/bindings/debug_memory/debug_memory.txt @@ -0,0 +1,22 @@ +Ramdump Debug Memory + +Debug memory contains necessary information for ramdump to dump +the memory.This memory is used as a bridge between Android and +ramdump. + +This memory is used by the modules mentioned below: +a) Rdtags +b) Ramdump Memory Descriptors + + +Required Properties: +-compatible: "removed-dma-pool", "qcom,debug_memory" +-reg: Specifies the physical address of the debug memory region and its size + +Example: + debug_region: debug_region@57e00000 { + compatible = "removed-dma-pool", "qcom,debug_memory"; + no-map; + reg = <0 0x57e00000 0 0x100000>; + label = "debug_mem"; + }; diff --git a/Documentation/devicetree/bindings/drm/msm/mdp.txt b/Documentation/devicetree/bindings/drm/msm/mdp.txt index a76b604445bd1644ba2f86b4c2c7bfed178a70b1..3a6db0553fe31ee8c1c7b86bea16ecd0a8e33c36 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdp.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdp.txt @@ -3,7 +3,6 @@ Qualcomm Technologies,Inc. Adreno/Snapdragon display controller Required properties: Optional properties: -- contiguous-region: reserved memory for HDMI and DSI buffer. - qcom,sde-plane-id-map: plane id mapping for virtual plane. - qcom,sde-plane-id: each virtual plane mapping node. - reg: reg property. @@ -18,8 +17,6 @@ Optional properties: Example: &mdss_mdp { - contiguous-region = <&cont_splash_mem &cont_splash_mem_hdmi>; - qcom,sde-plane-id-map { qcom,sde-plane-id@0 { reg = <0x0>; diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 80813dd1b3e54872d52d006cb230415268e09b61..d8c3a7c35465e88bfb350e55d29c4d0dbfce36a3 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -93,7 +93,6 @@ Optional Properties: - qcom,chipid: If it exists this property is used to replace the chip identification read from the GPU hardware. This is used to override faulty hardware readings. -- qcom,disable-wake-on-touch: Boolean. Disables the GPU power up on a touch input event. - qcom,disable-busy-time-burst: Boolean. Disables the busy time burst to avoid switching of power level for large frames based on the busy time limit. @@ -142,9 +141,6 @@ Optional Properties: rendering thread is running on masked CPUs. Bit 0 is for CPU-0, bit 1 is for CPU-1... -- qcom,l2pc-update-queue: - Disables L2PC on masked CPUs at queue time when it's true. - - qcom,snapshot-size: Specify the size of snapshot in bytes. This will override snapshot size defined in the driver code. diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index 176f9e115b4231328a72def913f72ca46b1d4e9c..abb15556037d7b41de90f31ea144498e471d3a51 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -78,6 +78,7 @@ Optional properties: - qcom,thermal-derate-current : Array of currrent limits for thermal mitigation. Required if qcom,thermal-derate-en is specified. Unit is mA. Format is qcom,thermal-derate-current = . + 0, 15, 30, 45 for pmi8998. - qcom,otst-ramp-back-up-dis : Boolean property to disable current ramp backup after thermal derate trigger is deasserted. diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt index 42e97f765bee494d6cc91a5cd491ef1922f8c731..1e6aac56c44efaafb910194970966bab3520e79d 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt @@ -78,8 +78,6 @@ Optional properties for WLED: - qcom,lcd-psm-ctrl : A boolean property to specify if PSM needs to be controlled dynamically when WLED module is enabled or disabled. -- qcom,auto-calibration-enable : A boolean property which enables auto-calibration - of the WLED sink configuration. Optional properties if 'qcom,disp-type-amoled' is mentioned in DT: - qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320. diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt index c5c82a89f66299790802001e2b0723ff790c5eed..9fb84020add729fdfdcc515b4f1b476a7094b0ae 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cci.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt @@ -123,9 +123,6 @@ Optional properties: - qcom,gpio-vdig : should contain index to gpio used by sensors digital vreg enable - qcom,gpio-vaf : should contain index to gpio used by sensors af vreg enable - qcom,gpio-af-pwdm : should contain index to gpio used by sensors af pwdm_n -- qcom,gpio-custom1 : should contain index to gpio used by sensors specific to usecase -- qcom,gpio-custom2 : should contain index to gpio used by sensors specific to usecase -- qcom,gpio-custom3 : should contain index to gpio used by sensors specific to usecase - qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor - qcom,gpio-req-tbl-flags : should contain direction of gpios present in qcom,gpio-req-tbl-num property (in the same order) @@ -205,31 +202,6 @@ Optional properties: (in the same order). - cam_vaf-supply : should contain regulator from which AF voltage is supplied -* Qualcomm Technologies, Inc. MSM LASER LED - -Required properties: -- cell-index : should contain unique identifier to differentiate - between multiple laser led modules -- reg : should contain i2c slave address of the laser led and length of - data field which is 0x0 -- compatible : - - "qcom,laser-led" -- qcom,cci-master : should contain i2c master id to be used for this camera - sensor - - 0 -> MASTER 0 - - 1 -> MASTER 1 - -Optional properties: -- qcom,cam-vreg-name : should contain names of all regulators needed by this - laser led -- qcom,cam-vreg-min-voltage : should contain minimum voltage level in microvolts - for regulators mentioned in qcom,cam-vreg-name property (in the same order) -- qcom,cam-vreg-max-voltage : should contain maximum voltage level in microvolts - for regulators mentioned in qcom,cam-vreg-name property (in the same order) -- qcom,cam-vreg-op-mode : should contain the maximum current in microamps - required from the regulators mentioned in the qcom,cam-vreg-name property - (in the same order). - * Qualcomm Technologies, Inc. MSM OIS Required properties: @@ -302,13 +274,6 @@ Example: qcom,cam-vreg-op-mode = <100000>; }; - laserled0: qcom,laserled@0 { - cell-index = <0>; - reg = <0x0>; - compatible = "qcom,laser-led"; - qcom,cci-master = <1>; - }; - qcom,camera@0 { cell-index = <0>; compatible = "qcom,camera"; diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt b/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt index c1a8d1bd697dc10ad399f5aeee847f698854cf11..acc8507732103351d23ef00c5bc6664cb532e51a 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt +++ b/Documentation/devicetree/bindings/net/wireless/qcom,wcn3990-wifi.txt @@ -11,24 +11,13 @@ Required properties: - compatible: "qcom,wcn3990-wifi"; - reg: Memory regions defined as starting address and size - reg-names: Names of the memory regions defined in reg entry - - clocks: List of clock phandles - - clock-names: List of clock names corresponding to the "clocks" property - interrupts: Copy engine interrupt table -Optional properties: - - -supply: phandle to the regulator device tree node - optional "supply-name" is "vdd-0.8-cx-mx". - - qcom,-config: Specifies voltage levels for supply. Should be - specified in pairs (min, max), units uV. There can - be optional load in uA and Regulator settle delay in - uS. Example: msm_ath10k_wlan: qcom,msm_ath10k_wlan@18800000 { compatible = "qcom,wcn3990-wifi"; reg = <0x18800000 0x800000>; reg-names = "membase"; - clocks = <&clock_gcc clk_aggre2_noc_clk>; - clock-names = "smmu_aggre2_noc_clk"; interrupts = <0 130 0 /* CE0 */ >, <0 131 0 /* CE1 */ >, @@ -42,10 +31,4 @@ Example: <0 139 0 /* CE9 */ >, <0 140 0 /* CE10 */ >, <0 141 0 /* CE11 */ >; - vdd-0.8-cx-mx-supply = <&pm8998_l5>; - vdd-1.8-xo-supply = <&pm8998_l7_pin_ctrl>; - vdd-1.3-rfa-supply = <&pm8998_l17_pin_ctrl>; - vdd-3.3-ch0-supply = <&pm8998_l25_pin_ctrl>; - qcom,vdd-0.8-cx-mx-config = <800000 800000>; - qcom,vdd-3.3-ch0-config = <3104000 3312000>; }; diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt index bf3ad8a71c26205ffb73cfcbdde99771fb9ff326..fc019bda50a7796918bbc93617d63f7e3b473bfa 100644 --- a/Documentation/devicetree/bindings/pci/msm_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt @@ -97,9 +97,6 @@ Optional Properties: and assign for each endpoint. - qcom,ep-latency: The time (unit: ms) to wait for the PCIe endpoint to become stable after power on, before de-assert the PERST to the endpoint. - - qcom,switch-latency: The time (unit: ms) to wait for the PCIe endpoint's link - training with switch downstream port after the link between switch upstream - port and RC is up. - qcom,wr-halt-size: With base 2, this exponent determines the size of the data that PCIe core will halt on for each write transaction. - qcom,cpl-timeout: Completion timeout value. This value specifies the time range @@ -279,7 +276,6 @@ Example: qcom,smmu-exist; qcom,smmu-sid-base = <0x1480>; qcom,ep-latency = <100>; - qcom,switch-latency = <100>; qcom,wr-halt-size = <0xa>; /* 1KB */ qcom,cpl-timeout = <0x2>; diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt index 406920b7246e7341a32a42d7874da21789524f53..47a6fdd300cae7deb0c8073928c42d415a277149 100644 --- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt +++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt @@ -88,7 +88,6 @@ Optional properties: - qcom,override-acc-1: Override the default ACC settings with this value if present. - qcom,cx-ipeak-vote: Boolean- Present if we need to set bit 5 of cxip_lm_vote_clear during modem shutdown -- qcom,minidump-id: Unique id for each subsystem One child node to represent the MBA image may be specified, when the MBA image needs to be loaded in a specifically carved out memory region. diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt index dd14890123e6e26b82f0f0b6596d4ba7940ebf34..babc4523a29a59fb877b28754132afbadde2a8a7 100644 --- a/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt +++ b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt @@ -9,8 +9,6 @@ Required properties: Optional property: - qcom,fab-id-valid: Use this property when support to read Fab identification from REV ID peripheral is available. -- qcom,tp-rev-valid: Use this property when support to read TP - revision identification from REV ID peripheral. Example: qcom,revid@100 { diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt index 8f35e56816cee57bdb628f6e9d6c5a0ef8a21fa1..96b7dd5172318466dada3f3e907fdefe90d3e45c 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt @@ -20,7 +20,6 @@ Required properties: Optional Properties: - qcom,external-rsense: To indicate whether the platform uses external or internal rsense for measuring battery current. -- qcom,enable-for-dc: To enable qnovo for dc charging path. Example: diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt index f01eae10bf4f2f945cbc7719d7272738c044b953..468db388b0a6ab1218e018d2e9de04f56a37e4e7 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt @@ -85,6 +85,21 @@ Charger specific properties: maximum charge current in mA for each thermal level. +- qcom,step-soc-thresholds + Usage: optional + Value type: Array of + Definition: Array of SOC threshold values, size of 4. This should be a + flat array that denotes the percentage ranging from 0 to 100. + If the array is not present, step charging is disabled. + +- qcom,step-current-deltas + Usage: optional + Value type: Array of + Definition: Array of delta values for charging current, size of 5, with + FCC as base. This should be a flat array that denotes the + offset of charging current in uA, from -3100000 to 3200000. + If the array is not present, step charging is disabled. + - io-channels Usage: optional Value type: List of @@ -167,22 +182,6 @@ Charger specific properties: Definition: Specifies the deglitch interval for OTG detection. If the value is not present, 50 msec is used as default. -- qcom,step-charging-enable - Usage: optional - Value type: bool - Definition: Boolean flag which when present enables step-charging. - -- qcom,wd-bark-time-secs - Usage: optional - Value type: - Definition: WD bark-timeout in seconds. The possible values are - 16, 32, 64, 128. If not defined it defaults to 64. - -- qcom,sw-jeita-enable - Usage: optional - Value type: bool - Definition: Boolean flag which when present enables sw compensation for jeita - ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= @@ -218,6 +217,9 @@ pmi8998_charger: qcom,qpnp-smb2 { dpdm-supply = <&qusb_phy0>; + qcom,step-soc-thresholds = <60 70 80 90>; + qcom,step-current-deltas = <500000 250000 150000 0 (-150000)>; + qcom,chgr@1000 { reg = <0x1000 0x100>; interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt index 376af82381f2877a48dff68276f3406d793bf2d5..f419655722d4ac62b44bf26c9412694471d33706 100644 --- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt +++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt @@ -11,8 +11,6 @@ Required properties: Optional properties: - qcom,fastrpc-glink: Flag to use glink instead of smd for IPC -- qcom,fastrpc-vmid-heap-shared: Flag for Dynamic heap feature, to - share HLOS memory buffer to ADSP Optional subnodes: - qcom,msm_fastrpc_compute_cb : Child nodes representing the compute context @@ -27,7 +25,6 @@ Example: qcom,msm_fastrpc { compatible = "qcom,msm-fastrpc-adsp"; qcom,fastrpc-glink; - qcom,fastrpc-vmid-heap-shared; qcom,msm_fastrpc_compute_cb_1 { compatible = "qcom,msm-fastrpc-compute-cb"; diff --git a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt index 1ac52d120daae811e8c2b2eceee5900138cdcf15..0d53b9fa4378897e562f0d23732f5b6e82bc9c04 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt @@ -86,11 +86,11 @@ LAB subnode required properties: 40 and 50. - interrupts: Specify the interrupts as per the interrupt encoding. - Currently "lab-vreg-ok" is required and "lab-sc_err" - is optional for LCD mode in pmi8998. - For AMOLED mode, "lab-vreg-ok" is required - only when SWIRE control is enabled and skipping - 2nd SWIRE pulse is required in pmi8952/8996. + Currently "lab-vreg-ok" is required for + LCD mode in pmi8998. For AMOLED mode, + "lab-vreg-ok" is required only when SWIRE + control is enabled and skipping 2nd SWIRE + pulse is required in pmi8952/8996. - interrupt-names: Interrupt names to match up 1-to-1 with the interrupts specified in 'interrupts' property. @@ -211,14 +211,6 @@ IBB subnode required properties: IBB subnode optional properties: -- interrupts: Specify the interrupts as per the interrupt - encoding. - Currently "ibb-sc-err" could be used for LCD mode - in pmi8998 to detect the short circuit fault. -- interrupt-names: Interrupt names to match up 1-to-1 with - the interrupts specified in 'interrupts' - property. - - qcom,qpnp-ibb-discharge-resistor: The discharge resistor in Kilo Ohms which controls the soft start time. Supported values are 300, 64, 32 and 16. diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt index 9798ac60b4931f96d9ba76daab50541a7e05a7cd..ed383ce9ea8faff3ce373ba75d98b9ea6176d457 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt @@ -209,12 +209,6 @@ Properties below are specific to BOOST subnode only. Definition: Current limit (in mA) of the BOOST rail. Possible values are 200 to 1600mA in 200mA steps. -- qcom,bst-headroom-mv - Usage: optional - Value type: - Definition: Headroom of the boost (in mV). The minimum headroom is - 200mV and if not specified defaults to 200mV. - ======= Example ======= @@ -256,6 +250,5 @@ pm660l_lcdb: qpnp-lcdb@ec00 { qcom,bst-pd-strength = <1>; qcom,bst-ps = <1>; qcom,bst-ps-threshold-ma = <50>; - qcom,bst-headroom-mv = <200>; }; }; diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index db21a2b58c2bf1658ef296483bef1dd8d901ec82..38e056cdc0ee0461c2c810ab1e61a00842f62ea6 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1311,13 +1311,6 @@ Optional properties: - pinctrl-x: Defines pinctrl state for each pin group. - - qcom,msm-cpudai-tdm-clk-attribute: Clock attribute for tdm. - 0 - Clk invalid attribute - 1 - Clk attribute couple no - 2 - Clk attribute couple dividend - 3 - Clk attribute couple divisor - 4 - Clk attribute invert couple no - Example: qcom,msm-dai-tdm-quat-rx { diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt index 9b40d44d363b92edefad185c7afdcff7644eb51a..88ad24900f289a05b02802f7d7712e6d6a132018 100644 --- a/Documentation/devicetree/bindings/usb/msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/msm-phy.txt @@ -214,8 +214,6 @@ Optional properties: - qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0 - qcom,vdda33-voltage-level: A list of three integer values (min, op, max) representing specific voltages (in microvolts) used for the vdda33 supply. - - qcom,tune2-efuse-correction: The value to be adjusted from fused value for - improved rise/fall times. Example: qusb_phy: qusb@f9b39000 { diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index 77d6bf06ee26c047d5441bf73a4572bb35835d0a..061c1d16ad24b13263382fcd66e2dc4d8f120e39 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -12,7 +12,7 @@ Required properties: "riva_ccu_base", "pronto_a2xb_base", "pronto_ccpu_base", "pronto_saw2_base", "wlan_tx_phy_aborts","wlan_brdg_err_source", "wlan_tx_status", "alarms_txctl", "alarms_tactl", - "pronto_mcu_base", "pronto_qfuse". + "pronto_mcu_base". - interupts: Pronto to Apps interrupts for tx done and rx pending. - qcom,pronto-vddmx-supply: regulator to supply pronto pll. - qcom,pronto-vddcx-supply: voltage corner regulator to supply WLAN/BT/FM @@ -29,7 +29,7 @@ Required properties: - qcom,wcnss-vadc: VADC handle for battery voltage notification APIs. - pinctrl- : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt - pinctrl-names : Names corresponding to the numbered pinctrl states -- clocks: from common clock binding: handle to xo, rf_clk and wcnss snoc clocks. +- clocks: from common clock binding: handle to xo and rf_clk clocks. - clock-names: Names of all the clocks that are accessed by the subsystem - qcom,vdd-voltage-level: This property represents (nominal, min, max) voltage for iris and pronto regulators in milli-volts. @@ -39,16 +39,11 @@ iris and pronto regulators in micro-amps. Optional properties: - qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect should be performed during boot up. -- qcom,snoc-wcnss-clock-freq: indicates the wcnss snoc clock frequency in Hz. -If wcnss_snoc clock is specified in the list of clocks, this property needs -to be set to make it functional. - qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value, using a smaller count for this buffer will reduce the memory usage. - qcom,is-pronto-v3: boolean flag to determine the pronto hardware version in use. subsequently correct workqueue will be used by DXE engine to push frames in TX data path. -- qcom,is-dual-band-disable: boolean flag to determine the WLAN dual band - capability. - qcom,is-pronto-vadc: boolean flag to determine Battery voltage feature support for pronto hardware. - qcom,wcnss-pm : , <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>; - qcom,wcn-external-gpio-support; qcom,has-48mhz-xo; qcom,is-pronto-vt; qcom,wlan-rx-buff-count = <512>; @@ -102,12 +94,7 @@ Example: clocks = <&clock_rpm clk_xo_wlan_clk>, <&clock_rpm clk_rf_clk2>, <&clock_debug clk_gcc_debug_mux>, - <&clock_gcc clk_wcnss_m_clk>, - <&clock_gcc clk_snoc_wcnss_a_clk>; - - clock-names = "xo", "rf_clk", "measure", "wcnss_debug", - "snoc_wcnss"; - - qcom,snoc-wcnss-clock-freq = <200000000>; + <&clock_gcc clk_wcnss_m_clk>; + clock-names = "xo", "rf_clk", "measure", "wcnss_debug"; qcom,wcnss-pm = <11 21 1200 1 1 6>; }; diff --git a/Documentation/vm/page_owner.txt b/Documentation/vm/page_owner.txt index ffff1439076a51af81c83e91602c9bfd08bed308..8f3ce9b3aa11b27c52bc20b395765b5df0833d71 100644 --- a/Documentation/vm/page_owner.txt +++ b/Documentation/vm/page_owner.txt @@ -28,11 +28,10 @@ with page owner and page owner is disabled in runtime due to no enabling boot option, runtime overhead is marginal. If disabled in runtime, it doesn't require memory to store owner information, so there is no runtime memory overhead. And, page owner inserts just two unlikely branches into -the page allocator hotpath and if not enabled, then allocation is done -like as the kernel without page owner. These two unlikely branches should -not affect to allocation performance, especially if the static keys jump -label patching functionality is available. Following is the kernel's code -size change due to this facility. +the page allocator hotpath and if it returns false then allocation is +done like as the kernel without page owner. These two unlikely branches +would not affect to allocation performance. Following is the kernel's +code size change due to this facility. - Without page owner text data bss dec hex filename diff --git a/Documentation/vm/z3fold.txt b/Documentation/vm/z3fold.txt new file mode 100644 index 0000000000000000000000000000000000000000..38e4dac810b62b2092f845d2a436ae15455ae9a4 --- /dev/null +++ b/Documentation/vm/z3fold.txt @@ -0,0 +1,26 @@ +z3fold +------ + +z3fold is a special purpose allocator for storing compressed pages. +It is designed to store up to three compressed pages per physical page. +It is a zbud derivative which allows for higher compression +ratio keeping the simplicity and determinism of its predecessor. + +The main differences between z3fold and zbud are: +* unlike zbud, z3fold allows for up to PAGE_SIZE allocations +* z3fold can hold up to 3 compressed pages in its page +* z3fold doesn't export any API itself and is thus intended to be used + via the zpool API. + +To keep the determinism and simplicity, z3fold, just like zbud, always +stores an integral number of compressed pages per page, but it can store +up to 3 pages unlike zbud which can store at most 2. Therefore the +compression ratio goes to around 2.7x while zbud's one is around 1.7x. + +Unlike zbud (but like zsmalloc for that matter) z3fold_alloc() does not +return a dereferenceable pointer. Instead, it returns an unsigned long +handle which encodes actual location of the allocated object. + +Keeping effective compression ratio close to zsmalloc's, z3fold doesn't +depend on MMU enabled and provides more predictable reclaim behavior +which makes it a better fit for small and response-critical systems. diff --git a/Makefile b/Makefile index ce92cd6345d7031bba12fc4985b9d293f3c8e3b7..85f821d8d07ccf35941ad8635a9866c12d3ec23e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 78 +SUBLEVEL = 74 EXTRAVERSION = NAME = Blurry Fish Butt @@ -637,12 +637,6 @@ endif # Tell gcc to never replace conditional load with a non-conditional one KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) -# check for 'asm goto' -ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y) - KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO - KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO -endif - ifdef CONFIG_READABLE_ASM # Disable optimizations that make assembler listings hard to read. # reorder blocks reorders the control in the function @@ -798,6 +792,12 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=date-time) # use the deterministic mode of AR if available KBUILD_ARFLAGS := $(call ar-option,D) +# check for 'asm goto' +ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y) + KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO + KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO +endif + include scripts/Makefile.kasan include scripts/Makefile.extrawarn include scripts/Makefile.ubsan diff --git a/README_Xperia b/README_Xperia new file mode 100644 index 0000000000000000000000000000000000000000..323a382280e5c5e00acd5e375383db620619252c --- /dev/null +++ b/README_Xperia @@ -0,0 +1,61 @@ +Configuration files can be found in arch/arm64/configs. + + defconfig using in common: + msmcortex-perf_defconfig + + diffconfigs for each product: + Xperia XZ1 G8341 => poplar_diffconfig + Xperia XZ1 G8342 => poplar_dsds_diffconfig + Xperia XZ1 Compact G8441 => lilac_diffconfig + + +How to build your kernel: + + Prerequisites: + + * ramdisk.img - root fs + + * mkbootimg - boot.img generator + + * The ARM cross-compiler + You can use prebuild executable binary which is included in + standard Android repository. Please visit to external site. + In case of this platform, we recommend to use gcc 4.9 or later + such as aarch64-linux-android-4.9 to avoid known issues. + + + Step 1: Build Your Kernel + $ cd kernel/msm-4.4 + + $ export ARCH=arm64 + + $ export PATH=:$PATH + NOTE: Please set the location of the ARM cross-compiler. + + $ export CROSS_COMPILE= + NOTE: Please set the prefix of the ARM cross-compiler. + ex) aarch64-linux-android- + + $ export KBUILD_DIFFCONFIG=poplar_diffconfig + NOTE: Please set a configuration file you want to build. + + $ make msmcortex-perf_defconfig O=./out + + $ make O=./out + + You can see arch/arm64/boot/Image-dtb if you succeed in building. + + + Step 2: Assembling the boot.img + (In the Linux Kernel directory) + $ mkbootimg \ + --kernel out/arch/arm64/boot/Image.gz-dtb \ + --ramdisk ramdisk.img \ + --cmdline "androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x37 ehci-hcd.park=3 lpm_levels.sleep_disabled=1 sched_enable_hmp=1 sched_enable_power_aware=1 service_locator.enable=1 zram.backend=z3fold buildvariant=userdebug" \ + --base 0x00000000 \ + --kernel_offset 0x00008000 \ + --ramdisk_offset 0x01000000 \ + --tags_offset 0x00000100 \ + --pagesize 4096 \ + -o boot.img + diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg index d1e3b0891a4ec4575ce8b07e52b48c5308634f3b..96edb3c844250e36f60e5ba0142789b7d176b25e 100644 --- a/android/configs/android-base.cfg +++ b/android/configs/android-base.cfg @@ -17,6 +17,7 @@ CONFIG_AUDIT=y CONFIG_BLK_DEV_INITRD=y CONFIG_CGROUPS=y CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_SCHED=y CONFIG_DEFAULT_SECURITY_SELINUX=y diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 22b546e0f8451145d51bf98d6f2e219c5e119256..0c9493b4c80833dc1c3db7f9ef408356d42a9c0c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -3,6 +3,7 @@ config ARM default y select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_ELF_RANDOMIZE + select ARCH_HAS_CRASH_NOTES if CRASH_NOTES select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAVE_CUSTOM_GPIO_H select ARCH_HAS_GCOV_PROFILE_ALL @@ -196,6 +197,9 @@ config ARCH_HAS_BANDGAP config FIX_EARLYCON_MEM def_bool y if MMU +config ARCH_HAS_CRASH_NOTES + bool + config GENERIC_HWEIGHT bool default y @@ -1776,7 +1780,7 @@ source "mm/Kconfig" choice prompt "Virtual Memory Reclaim" - default ENABLE_VMALLOC_SAVING + default NO_VM_RECLAIM help Select the method of reclaiming virtual memory @@ -2118,6 +2122,14 @@ config CRASH_DUMP For more details see Documentation/kdump/kdump.txt +config CRASH_NOTES + bool "Support storing crash notes at panic" + depends on !KEXEC + help + Generate kdump style crash notes at the time of a panic and fill it + with the crashed context to support analysis of the memory dump with + tools like Redhat CRASH. + config AUTO_ZRELADDR bool "Auto calculation of the decompressed kernel image address" help diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi index de8ac998604ded57b0e149bea64dae9fd3ec869c..6f50f672efbdf754f200f67b9f4e1518d91f6a26 100644 --- a/arch/arm/boot/dts/bcm5301x.dtsi +++ b/arch/arm/boot/dts/bcm5301x.dtsi @@ -54,14 +54,14 @@ timer@0200 { compatible = "arm,cortex-a9-global-timer"; reg = <0x0200 0x100>; - interrupts = ; + interrupts = ; clocks = <&clk_periph>; }; local-timer@0600 { compatible = "arm,cortex-a9-twd-timer"; reg = <0x0600 0x100>; - interrupts = ; + interrupts = ; clocks = <&clk_periph>; }; diff --git a/arch/arm/boot/dts/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom-msm8660.dtsi index e5f7f33aa4677739f9bc1e6d57d969db9b856cf9..576211b74e2fc0a0d0fd69214e4d5bf1b28f9729 100644 --- a/arch/arm/boot/dts/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom-msm8660.dtsi @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /dts-v1/; /include/ "skeleton.dtsi" diff --git a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts index 016f9ad9392a9cbad2702834aff6648add614b7b..5b785e6fbae9726df05d06dd51f92fdd578f3b25 100644 --- a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts +++ b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "qcom-msm8974.dtsi" #include "qcom-pm8841.dtsi" #include "qcom-pm8941.dtsi" diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index 753bdfddd46ea5d503c8409cc5c035b239efe47c..76f5d68acf66df50ed787d83d82170fbebac15fb 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /dts-v1/; #include diff --git a/arch/arm/boot/dts/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom-pm8941.dtsi index b0d443999fcccb84d3301e7787c292830a596e86..60b565335ffa16a1db10e3aa8526c9e3c5e99409 100644 --- a/arch/arm/boot/dts/qcom-pm8941.dtsi +++ b/arch/arm/boot/dts/qcom-pm8941.dtsi @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index ec4b6516e44836e98f8ed9ee62d1c2781aa0dd36..760916ba46dd35d4a456a963f01e574b949550b0 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -116,6 +116,7 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \ dtb-$(CONFIG_MSM_GVM_QUIN) += vplatform-lfv-msm8996.dtb +ifneq ($(CONFIG_ARCH_SONY_YOSHINO),y) ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) dtbo-$(CONFIG_ARCH_MSM8998) += \ msm8998-cdp-overlay.dtbo \ @@ -168,13 +169,20 @@ dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \ apq8098-v2.1-cdp.dtb \ apq8098-v2.1-qrd.dtb \ apq8098-v2.1-mediabox.dtb \ - apq8098-v2.1-svr20.dtb \ msm8998-v2.1-interposer-sdm660-cdp.dtb \ msm8998-v2.1-interposer-sdm660-mtp.dtb \ - msm8998-v2.1-interposer-sdm660-qrd.dtb \ - msm8998-9x55-rcm.dtb \ - msm8998-9x55-cdp.dtb \ - msm8998-9x55-mtp.dtb + msm8998-v2.1-interposer-sdm660-qrd.dtb +endif +else +dtb-$(CONFIG_MACH_SONY_POPLAR) += msm8998-yoshino-poplar_generic.dtb \ + msm8998-v2-yoshino-poplar_generic.dtb \ + msm8998-v2.1-yoshino-poplar_generic.dtb +dtb-$(CONFIG_MACH_SONY_POPLAR_DSDS) += msm8998-yoshino-poplar_dsds.dtb \ + msm8998-v2-yoshino-poplar_dsds.dtb \ + msm8998-v2.1-yoshino-poplar_dsds.dtb +dtb-$(CONFIG_MACH_SONY_LILAC) += msm8998-yoshino-lilac_generic.dtb \ + msm8998-v2-yoshino-lilac_generic.dtb \ + msm8998-v2.1-yoshino-lilac_generic.dtb endif dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb @@ -229,34 +237,7 @@ dtb-$(CONFIG_ARCH_SDM660) += sdm660-sim.dtb \ sda658-rcm.dtb \ sda658-pm660a-mtp.dtb \ sda658-pm660a-cdp.dtb \ - sda658-pm660a-rcm.dtb \ - sdm636-cdp.dtb \ - sdm636-mtp.dtb \ - sdm636-qrd.dtb \ - sdm636-rcm.dtb \ - sdm636-headset-jacktype-no-cdp.dtb \ - sdm636-headset-jacktype-no-rcm.dtb \ - sdm636-internal-codec-cdp.dtb \ - sdm636-internal-codec-mtp.dtb \ - sdm636-internal-codec-pm660a-cdp.dtb \ - sdm636-internal-codec-pm660a-mtp.dtb \ - sdm636-internal-codec-pm660a-rcm.dtb \ - sdm636-internal-codec-rcm.dtb \ - sdm636-pm660a-headset-jacktype-no-cdp.dtb \ - sdm636-pm660a-headset-jacktype-no-rcm.dtb \ - sdm636-pm660a-cdp.dtb \ - sdm636-pm660a-mtp.dtb \ - sdm636-pm660a-qrd.dtb \ - sdm636-pm660a-rcm.dtb \ - sdm636-usbc-audio-mtp.dtb \ - sdm636-usbc-audio-rcm.dtb \ - sda636-cdp.dtb \ - sda636-mtp.dtb \ - sda636-rcm.dtb \ - sda636-pm660a-cdp.dtb \ - sda636-pm660a-mtp.dtb \ - sda636-pm660a-qrd-hdk.dtb \ - sda636-pm660a-rcm.dtb + sda658-pm660a-rcm.dtb dtb-$(CONFIG_ARCH_SDM630) += sdm630-rumi.dtb \ sdm630-pm660a-rumi.dtb \ diff --git a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi index db33594d3827b3da8adb65982c3585de75574a6e..4081a21b3134911db3dba86a37a4c85211c3197f 100644 --- a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi +++ b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi @@ -713,10 +713,6 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, - <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, - <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, - <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, - <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -735,10 +731,6 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", - "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", - "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", - "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", - "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", diff --git a/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts index 1fa49d8a060d344e9f3f5f3fc8521056af8b717b..bd29c03075764803ef0cbc10478ae990bacb0d33 100644 --- a/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts +++ b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts @@ -101,10 +101,6 @@ status = "disabled"; }; -&pcie0 { - qcom,boot-option = <0x0>; -}; - &soc { qcom,msm-dai-mi2s { dai_mi2s3: qcom,msm-dai-q6-mi2s-quat { diff --git a/arch/arm/boot/dts/qcom/clearpad-ic-default-regoffset.dtsi b/arch/arm/boot/dts/qcom/clearpad-ic-default-regoffset.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1bffd1fe8e2fbb71ed5c97a2b3c7d5b64cdb49f2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/clearpad-ic-default-regoffset.dtsi @@ -0,0 +1,45 @@ +/* + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +synaptics_clearpad@2c { +/* Write area------------------------------------------ */ + + somc,clearpad-f01-rmi-cmd00 = <0x00>; + somc,clearpad-f01-rmi-ctrl00 = <0x00>; + somc,clearpad-f01-rmi-ctrl01 = <0x01>; + somc,clearpad-f01-rmi-data00 = <0x00>; + somc,clearpad-f01-rmi-data01 = <0x01>; + somc,clearpad-f01-rmi-query11 = <0x0B>; + + somc,clearpad-f34-flash-ctrl00 = <0x00>; + somc,clearpad-f34-flash-data00 = <0x00>; + somc,clearpad-f34-flash-data01 = <0x01>; + somc,clearpad-f34-flash-data02 = <0x02>; + somc,clearpad-f34-flash-data03 = <0x03>; + somc,clearpad-f34-flash-data04 = <0x04>; + somc,clearpad-f34-flash-data05 = <0x05>; + somc,clearpad-f34-flash-query00 = <0x00>; + somc,clearpad-f34-flash-query01 = <0x01>; + somc,clearpad-f34-flash-query03 = <0x03>; + +/* Write area------------------------------------------ */ +}; + +#include "clearpad-ic-s332u-regoffset.dtsi" +#include "clearpad-ic-s3330-regoffset.dtsi" +#include "clearpad-ic-s3500-regoffset.dtsi" diff --git a/arch/arm/boot/dts/qcom/clearpad-ic-s332u-regoffset.dtsi b/arch/arm/boot/dts/qcom/clearpad-ic-s332u-regoffset.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9b41541db1e4465df4a694cf59b759ac839f63b3 --- /dev/null +++ b/arch/arm/boot/dts/qcom/clearpad-ic-s332u-regoffset.dtsi @@ -0,0 +1,88 @@ +/* + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +synaptics_clearpad@2c { + S332U { + /* Write area------------------------------------------ */ + + EXTRA_0x05 { + somc,clearpad-f01-rmi-cmd00 = <0x00>; + somc,clearpad-f01-rmi-ctrl00 = <0x00>; + somc,clearpad-f01-rmi-ctrl01 = <0x01>; + somc,clearpad-f01-rmi-ctrl05 = <0x02>; + somc,clearpad-f01-rmi-ctrl18 = <0x04>; + somc,clearpad-f01-rmi-data00 = <0x00>; + somc,clearpad-f01-rmi-data01 = <0x01>; + somc,clearpad-f01-rmi-query11 = <0x0B>; + + somc,clearpad-f12-2d-ctrl08 = <0x00>; + + somc,clearpad-f34-flash-ctrl00 = <0x00>; + somc,clearpad-f34-flash-data00 = <0x00>; + somc,clearpad-f34-flash-data01 = <0x01>; + somc,clearpad-f34-flash-data02 = <0x02>; + somc,clearpad-f34-flash-data03 = <0x03>; + somc,clearpad-f34-flash-data04 = <0x04>; + somc,clearpad-f34-flash-data05 = <0x05>; + somc,clearpad-f34-flash-query01 = <0x01>; + somc,clearpad-f34-flash-query03 = <0x03>; + + somc,clearpad-f54-analog-cmd00 = <0x00>; + somc,clearpad-f54-analog-ctrl188 = <0x1D>; + somc,clearpad-f54-analog-data00 = <0x00>; + somc,clearpad-f54-analog-data01 = <0x01>; + somc,clearpad-f54-analog-data02 = <0x02>; + somc,clearpad-f54-analog-data03 = <0x03>; + somc,clearpad-f54-analog-data31 = <0x0E>; + }; + + EXTRA_0x06 { + somc,clearpad-f01-rmi-cmd00 = <0x00>; + somc,clearpad-f01-rmi-ctrl00 = <0x00>; + somc,clearpad-f01-rmi-ctrl01 = <0x01>; + somc,clearpad-f01-rmi-ctrl05 = <0x02>; + somc,clearpad-f01-rmi-ctrl18 = <0x04>; + somc,clearpad-f01-rmi-data00 = <0x00>; + somc,clearpad-f01-rmi-data01 = <0x01>; + somc,clearpad-f01-rmi-query11 = <0x0B>; + + somc,clearpad-f12-2d-ctrl08 = <0x00>; + + somc,clearpad-f34-flash-ctrl00 = <0x00>; + somc,clearpad-f34-flash-data00 = <0x00>; + somc,clearpad-f34-flash-data01 = <0x01>; + somc,clearpad-f34-flash-data02 = <0x02>; + somc,clearpad-f34-flash-data03 = <0x03>; + somc,clearpad-f34-flash-data04 = <0x04>; + somc,clearpad-f34-flash-data05 = <0x05>; + somc,clearpad-f34-flash-query01 = <0x01>; + somc,clearpad-f34-flash-query03 = <0x03>; + + somc,clearpad-f54-analog-cmd00 = <0x00>; + somc,clearpad-f54-analog-ctrl188 = <0x1F>; + somc,clearpad-f54-analog-data00 = <0x00>; + somc,clearpad-f54-analog-data01 = <0x01>; + somc,clearpad-f54-analog-data02 = <0x02>; + somc,clearpad-f54-analog-data03 = <0x03>; + somc,clearpad-f54-analog-data31 = <0x0E>; + }; + + /* Write area------------------------------------------ */ + }; +}; + diff --git a/arch/arm/boot/dts/qcom/clearpad-ic-s3330-regoffset.dtsi b/arch/arm/boot/dts/qcom/clearpad-ic-s3330-regoffset.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4fa6045a327185ccc3eb94b25a995bb8d6d4c424 --- /dev/null +++ b/arch/arm/boot/dts/qcom/clearpad-ic-s3330-regoffset.dtsi @@ -0,0 +1,94 @@ +/* + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +synaptics_clearpad@2c { + S3330 { + /* Write area------------------------------------------ */ + + EXTRA_0x05 { + somc,clearpad-f01-rmi-cmd00 = <0x00>; + somc,clearpad-f01-rmi-ctrl00 = <0x00>; + somc,clearpad-f01-rmi-ctrl01 = <0x01>; + somc,clearpad-f01-rmi-ctrl05 = <0x04>; + somc,clearpad-f01-rmi-data00 = <0x00>; + somc,clearpad-f01-rmi-data01 = <0x01>; + somc,clearpad-f01-rmi-query11 = <0x0B>; + + somc,clearpad-f12-2d-ctrl08 = <0x00>; + + somc,clearpad-f34-flash-ctrl00 = <0x00>; + somc,clearpad-f34-flash-data00 = <0x00>; + somc,clearpad-f34-flash-data01 = <0x01>; + somc,clearpad-f34-flash-data02 = <0x02>; + somc,clearpad-f34-flash-data03 = <0x03>; + somc,clearpad-f34-flash-data04 = <0x04>; + somc,clearpad-f34-flash-data05 = <0x05>; + somc,clearpad-f34-flash-query01 = <0x01>; + somc,clearpad-f34-flash-query03 = <0x03>; + + somc,clearpad-f54-analog-cmd00 = <0x00>; + somc,clearpad-f54-analog-ctrl109 = <0x3a>; + somc,clearpad-f54-analog-ctrl113 = <0x3b>; + somc,clearpad-f54-analog-ctrl147 = <0x42>; + somc,clearpad-f54-analog-ctrl214 = <0x53>; + somc,clearpad-f54-analog-data00 = <0x00>; + somc,clearpad-f54-analog-data01 = <0x01>; + somc,clearpad-f54-analog-data02 = <0x02>; + somc,clearpad-f54-analog-data03 = <0x03>; + somc,clearpad-f54-analog-data31 = <0x0E>; + somc,clearpad-f54-analog-query38 = <0x1E>; + }; + + EXTRA_0x06 { + somc,clearpad-f01-rmi-cmd00 = <0x00>; + somc,clearpad-f01-rmi-ctrl00 = <0x00>; + somc,clearpad-f01-rmi-ctrl01 = <0x01>; + somc,clearpad-f01-rmi-ctrl05 = <0x04>; + somc,clearpad-f01-rmi-data00 = <0x00>; + somc,clearpad-f01-rmi-data01 = <0x01>; + somc,clearpad-f01-rmi-query11 = <0x0B>; + + somc,clearpad-f12-2d-ctrl08 = <0x00>; + + somc,clearpad-f34-flash-ctrl00 = <0x00>; + somc,clearpad-f34-flash-data00 = <0x00>; + somc,clearpad-f34-flash-data01 = <0x01>; + somc,clearpad-f34-flash-data02 = <0x02>; + somc,clearpad-f34-flash-data03 = <0x03>; + somc,clearpad-f34-flash-data04 = <0x04>; + somc,clearpad-f34-flash-data05 = <0x05>; + somc,clearpad-f34-flash-query01 = <0x01>; + somc,clearpad-f34-flash-query03 = <0x03>; + + somc,clearpad-f54-analog-cmd00 = <0x00>; + somc,clearpad-f54-analog-ctrl88 = <0x26>; + somc,clearpad-f54-analog-ctrl109 = <0x38>; + somc,clearpad-f54-analog-ctrl113 = <0x39>; + somc,clearpad-f54-analog-ctrl147 = <0x40>; + somc,clearpad-f54-analog-ctrl214 = <0x53>; + somc,clearpad-f54-analog-data00 = <0x00>; + somc,clearpad-f54-analog-data01 = <0x01>; + somc,clearpad-f54-analog-data02 = <0x02>; + somc,clearpad-f54-analog-data03 = <0x03>; + somc,clearpad-f54-analog-query38 = <0x1E>; + }; + + /* Write area------------------------------------------ */ + }; +}; + diff --git a/arch/arm/boot/dts/qcom/clearpad-ic-s3500-regoffset.dtsi b/arch/arm/boot/dts/qcom/clearpad-ic-s3500-regoffset.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..678b4fba7b7eeffe5348fcc821eb9dee4d89293d --- /dev/null +++ b/arch/arm/boot/dts/qcom/clearpad-ic-s3500-regoffset.dtsi @@ -0,0 +1,63 @@ +/* + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +synaptics_clearpad@2c { + S3500 { + /* Write area------------------------------------------ */ + + EXTRA_0x03 { + somc,clearpad-f01-rmi-cmd00 = <0x00>; + somc,clearpad-f01-rmi-ctrl00 = <0x00>; + somc,clearpad-f01-rmi-ctrl01 = <0x01>; + somc,clearpad-f01-rmi-ctrl05 = <0x04>; + somc,clearpad-f01-rmi-data00 = <0x00>; + somc,clearpad-f01-rmi-data01 = <0x01>; + somc,clearpad-f01-rmi-query11 = <0x0B>; + + somc,clearpad-f12-2d-ctrl08 = <0x00>; + + somc,clearpad-f34-flash-ctrl00 = <0x00>; + somc,clearpad-f34-flash-data00 = <0x00>; + somc,clearpad-f34-flash-data01 = <0x01>; + somc,clearpad-f34-flash-data02 = <0x02>; + somc,clearpad-f34-flash-data03 = <0x03>; + somc,clearpad-f34-flash-query00 = <0x00>; + somc,clearpad-f34-flash-query01 = <0x01>; + somc,clearpad-f34-flash-query03 = <0x03>; + + somc,clearpad-f51-custom-ctrl05 = <0x00>; + somc,clearpad-f51-custom-ctrl30 = <0x86>; + + somc,clearpad-f54-analog-cmd00 = <0x00>; + somc,clearpad-f54-analog-ctrl113 = <0x25>; + somc,clearpad-f54-analog-ctrl147 = <0x2F>; + somc,clearpad-f54-analog-ctrl149 = <0x30>; + somc,clearpad-f54-analog-ctrl41 = <0x14>; + somc,clearpad-f54-analog-ctrl57 = <0x17>; + somc,clearpad-f54-analog-ctrl88 = <0x19>; + somc,clearpad-f54-analog-data00 = <0x00>; + somc,clearpad-f54-analog-data01 = <0x01>; + somc,clearpad-f54-analog-data02 = <0x02>; + somc,clearpad-f54-analog-data03 = <0x03>; + somc,clearpad-f54-analog-query38 = <0x1E>; + }; + + /* Write area------------------------------------------ */ + }; +}; + diff --git a/arch/arm/boot/dts/qcom/dsi-panel-lilac-id5_pcc.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-lilac-id5_pcc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..826d0286142fad0fa35b41b53330aff3e00c74ff --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-lilac-id5_pcc.dtsi @@ -0,0 +1,717 @@ +/* arch/arm64/boot/dts/qcom/dsi-panel-lilac-id5_pcc.dtsi + * + * 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +/* pcc-table for Lilac LGD */ +&mdss_mdp { + dsi_5: somc,5_panel { + somc,mdss-dsi-pcc-enable; + somc,mdss-dsi-uv-command = [ + 06 01 00 00 00 00 01 DA + 06 01 00 00 00 00 01 DB]; + somc,mdss-dsi-uv-param-type = <4>; + somc,mdss-dsi-pcc-table-size = <226>; + somc,mdss-dsi-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x2E00 0x5800 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x3180 0x5780 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x3500 0x5700 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x3800 0x5700 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x3C00 0x5680 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x3E80 0x5600 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x4280 0x5580 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x4600 0x5500 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x4A00 0x5500 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x4E00 0x5480 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x5280 0x5400 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x5800 0x5400 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x5D00 0x5380 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x6280 0x5380 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x6800 0x5300 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x3400 0x5E80 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x3700 0x5E00 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x3A80 0x5D00 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x3D80 0x5C80 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x4080 0x5C00 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x4400 0x5B80 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x4780 0x5B00 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x4B80 0x5A80 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x4F80 0x5A00 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x5400 0x5A00 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x5880 0x5980 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x5D80 0x5900 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x6300 0x5880 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x6800 0x5800 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x6F80 0x5800 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x3900 0x6380 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x3C80 0x6300 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x3F00 0x6280 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x4200 0x6200 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x4580 0x6100 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x4900 0x6100 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x4C80 0x6080 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x5000 0x5F80 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x5500 0x5F00 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x5980 0x5E80 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x5E80 0x5E80 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x6300 0x5E00 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x6880 0x5D80 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x6F80 0x5D00 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x7500 0x5C80 0x8000 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x3E00 0x6A00 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x4080 0x6900 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x4380 0x6880 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x4700 0x6700 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x4A00 0x6680 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x4D80 0x6600 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x5180 0x6500 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x5600 0x6480 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x5A80 0x6380 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x5F00 0x6300 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x6380 0x6280 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x6880 0x6280 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x6F80 0x6180 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x7500 0x6100 0x8000 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x7980 0x6100 0x8000 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x4200 0x7180 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x4500 0x7080 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x4800 0x7000 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x4B80 0x6E80 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x4E80 0x6D00 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x5280 0x6B80 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x5700 0x6B00 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x5B00 0x6A00 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x5F80 0x6900 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x6380 0x6880 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x6880 0x6700 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x6F80 0x6700 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x7500 0x6680 0x8000 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x7900 0x6580 0x8000 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x6400 0x7D80 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x4680 0x7680 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x4980 0x7600 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x4C80 0x7500 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x5000 0x7480 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x5380 0x7380 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x5800 0x7280 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x5B80 0x7200 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x6000 0x7100 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x6400 0x7000 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x6900 0x6F00 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x6F80 0x6D80 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x7500 0x6C80 0x8000 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x7900 0x6B80 0x8000 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x6A80 0x8000 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x6380 0x7900 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x4A80 0x7B00 0x8000 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x4D80 0x7A80 0x8000 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x5080 0x7980 0x8000 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x5480 0x7880 0x8000 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x5800 0x7800 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x5C00 0x7700 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x6080 0x7680 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x6400 0x7600 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x6900 0x7500 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x6F80 0x7480 0x8000 + 0x00 0x65 0x14 0x16 0x20 0x22 0x7480 0x7380 0x8000 + 0x00 0x66 0x11 0x13 0x20 0x22 0x7880 0x7280 0x8000 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x7200 0x8000 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x6A00 0x7A00 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x6300 0x7500 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x4B00 0x8000 0x7B00 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x4F00 0x8000 0x7B80 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x5380 0x8000 0x7D80 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x5880 0x8000 0x8000 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x5C80 0x7D80 0x8000 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x6100 0x7B00 0x8000 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x6480 0x7A80 0x8000 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x6900 0x7980 0x8000 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x6F80 0x7900 0x8000 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x7480 0x7800 0x8000 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x7800 0x7780 0x8000 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x7D80 0x7680 0x8000 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7200 0x7A80 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x6980 0x7680 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x6280 0x6F00 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x4980 0x8000 0x7700 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x4D80 0x8000 0x7800 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x5280 0x8000 0x7900 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x5800 0x8000 0x7A00 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x5C80 0x8000 0x7A80 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x6180 0x8000 0x7B80 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x6680 0x8000 0x7C00 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x6D00 0x8000 0x7D80 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7400 0x8000 0x8000 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x7800 0x7D00 0x8000 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x8000 0x8000 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7800 0x7B00 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7200 0x7780 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x6900 0x7100 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x6200 0x6A00 + 0x00 0x88 0x32 0x34 0x17 0x19 0x4800 0x8000 0x7100 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x4C80 0x8000 0x7380 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x5100 0x8000 0x7500 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x5680 0x8000 0x7600 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x5B00 0x8000 0x7700 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x6100 0x8000 0x7880 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x6600 0x8000 0x7900 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x6C80 0x8000 0x7980 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7380 0x8000 0x7A00 + 0x00 0x91 0x17 0x19 0x17 0x19 0x7800 0x8000 0x7B00 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x8000 0x7B80 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7800 0x7800 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7200 0x7380 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x6900 0x6C00 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x6180 0x6600 + 0x00 0x97 0x32 0x34 0x14 0x16 0x4680 0x8000 0x6B80 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x4B80 0x8000 0x6D00 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x5000 0x8000 0x6E80 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x5580 0x8000 0x7080 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x5A80 0x8000 0x7200 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x6000 0x8000 0x7400 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x6500 0x8000 0x7500 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x6B00 0x8000 0x7600 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7300 0x8000 0x7700 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x7780 0x8000 0x7800 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x8000 0x7880 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7800 0x7480 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x7180 0x6E00 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x6800 0x6800 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x6100 0x6280 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x4580 0x8000 0x6700 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x4980 0x8000 0x6800 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x4E80 0x8000 0x6980 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x5400 0x8000 0x6B00 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x5980 0x8000 0x6C80 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x5F00 0x8000 0x6E00 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x6400 0x8000 0x7000 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x6A80 0x8000 0x7100 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7200 0x8000 0x7280 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x7780 0x8000 0x7400 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x7D80 0x8000 0x7580 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7800 0x7000 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x7180 0x6980 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x6780 0x6500 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x6080 0x5F80 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x4380 0x8000 0x6380 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x4880 0x8000 0x6500 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x4D80 0x8000 0x6600 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x5280 0x8000 0x6780 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x5880 0x8000 0x6800 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x5E00 0x8000 0x6980 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x6380 0x8000 0x6B00 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x6980 0x8000 0x6C00 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7180 0x8000 0x6E00 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x7700 0x8000 0x6F00 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x7D80 0x8000 0x7080 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7800 0x6B80 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x7180 0x6680 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x6780 0x6200 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x5F80 0x5C80 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x4200 0x8000 0x5F80 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x4780 0x8000 0x6100 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x4C00 0x8000 0x6300 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x5100 0x8000 0x6400 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x5780 0x8000 0x6580 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x5D00 0x8000 0x6600 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x6300 0x8000 0x6780 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x6900 0x8000 0x6880 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7100 0x8000 0x6980 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x7700 0x8000 0x6B00 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x7B80 0x8000 0x6C00 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7800 0x6800 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x7100 0x6400 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x6700 0x5E80 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x5F00 0x5980 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x4080 0x8000 0x5C00 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x4580 0x8000 0x5E00 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x4B00 0x8000 0x5F00 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x5000 0x8000 0x6080 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x5680 0x8000 0x6200 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x5C00 0x8000 0x6300 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x6200 0x8000 0x6480 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x6800 0x8000 0x6600 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7080 0x8000 0x6680 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x7680 0x8000 0x6800 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x7B80 0x8000 0x6880 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7800 0x6600 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x7100 0x6100 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x6700 0x5C00 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x5E80 0x5700 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-srgb-pcc-enable; + somc,mdss-dsi-srgb-pcc-table-size = <226>; + somc,mdss-dsi-srgb-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x2E80 0x5A80 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x3180 0x5A00 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x3500 0x5980 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x3880 0x5900 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x3C00 0x5880 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x4000 0x5800 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x4400 0x5780 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x4800 0x5780 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x4B80 0x5700 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x4F80 0x5700 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x5480 0x5700 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x5900 0x5680 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x5F00 0x5680 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x6480 0x5600 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x6A00 0x5580 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x3380 0x6180 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x3780 0x6080 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x3A80 0x6000 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x3E00 0x5F80 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x4180 0x5E80 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x4580 0x5E00 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x4980 0x5D80 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x4D00 0x5D00 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x5080 0x5C80 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x5580 0x5C00 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x5A00 0x5B80 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x6000 0x5B00 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x6500 0x5B00 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x6A00 0x5A80 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x7180 0x5A00 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x3980 0x6700 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x3D00 0x6600 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x4080 0x6580 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x4380 0x6500 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x4780 0x6400 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x4A80 0x6400 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x4E00 0x6380 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x5200 0x6300 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x5600 0x6280 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x5B00 0x6200 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x6080 0x6180 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x6580 0x6100 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x6A80 0x6080 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x7180 0x6000 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x7780 0x5F80 0x8000 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x3E80 0x6D00 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x4200 0x6B80 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x4500 0x6B00 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x4880 0x6A00 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x4B80 0x6980 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x4F00 0x6880 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x5300 0x6800 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x5700 0x6700 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x5C00 0x6700 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x6180 0x6680 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x6600 0x6600 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x6A80 0x6580 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x7180 0x6480 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x7700 0x6480 0x8000 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x7B80 0x6400 0x8000 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x4380 0x7480 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x4700 0x7300 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x4980 0x7280 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x4D00 0x7100 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x5000 0x6F80 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x5400 0x6E80 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x5800 0x6D80 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x5C80 0x6D00 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x6200 0x6B80 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x6600 0x6B00 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x6A80 0x6A80 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x7180 0x6980 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x7700 0x6900 0x8000 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x7B80 0x6880 0x8000 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x6700 0x7F00 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x4800 0x7900 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x4B00 0x7800 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x4D80 0x7780 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x5100 0x7700 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x5500 0x7600 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x5900 0x7500 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x5D80 0x7480 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x6280 0x7400 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x6680 0x7280 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x6B00 0x7180 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x7180 0x7000 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x7680 0x6F80 0x8000 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x7B00 0x6E00 0x8000 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x6D80 0x8000 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x6680 0x7A80 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x4C00 0x7E00 0x8000 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x4F00 0x7D00 0x8000 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x5200 0x7C00 0x8000 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x5580 0x7B00 0x8000 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x5980 0x7A00 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x5E00 0x7980 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x6300 0x7900 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x6700 0x7800 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x6B00 0x7780 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x7180 0x7680 0x8000 + 0x00 0x65 0x14 0x16 0x20 0x22 0x7680 0x7600 0x8000 + 0x00 0x66 0x11 0x13 0x20 0x22 0x7A80 0x7500 0x8000 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x7480 0x8000 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x6D00 0x7B00 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x6600 0x7600 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x4C00 0x8000 0x7C00 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x5000 0x8000 0x7D80 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x5580 0x8000 0x7E80 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x5A00 0x8000 0x8000 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x5E80 0x7F80 0x8000 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x6300 0x7E00 0x8000 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x6700 0x7D00 0x8000 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x6B00 0x7C80 0x8000 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x7180 0x7B80 0x8000 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x7600 0x7A80 0x8000 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x7A00 0x7A00 0x8000 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x7F00 0x7980 0x8000 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7480 0x7C00 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x6C00 0x7700 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x6580 0x7000 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x4B00 0x8000 0x7800 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x4F80 0x8000 0x7900 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x5400 0x8000 0x7A00 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x5900 0x8000 0x7A80 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x5E00 0x8000 0x7C00 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x6400 0x8000 0x7C80 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x6880 0x8000 0x7E00 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x6F80 0x8000 0x7F00 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7600 0x8000 0x8000 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x7A00 0x7F80 0x8000 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x8000 0x8000 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7A00 0x7C00 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7480 0x7880 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x6B80 0x7200 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x6500 0x6B00 + 0x00 0x88 0x32 0x34 0x17 0x19 0x4980 0x8000 0x7280 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x4D80 0x8000 0x7400 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x5280 0x8000 0x7580 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x5780 0x8000 0x7680 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x5D00 0x8000 0x7800 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x6300 0x8000 0x7880 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x6800 0x8000 0x7980 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x6E00 0x8000 0x7A80 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7580 0x8000 0x7B80 + 0x00 0x91 0x17 0x19 0x17 0x19 0x7A00 0x8000 0x7C00 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x8000 0x7D80 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7A00 0x7900 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7480 0x7400 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x6B80 0x6D00 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x6480 0x6700 + 0x00 0x97 0x32 0x34 0x14 0x16 0x4800 0x8000 0x6C00 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x4C80 0x8000 0x6E00 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x5100 0x8000 0x6F80 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x5680 0x8000 0x7100 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x5C00 0x8000 0x7380 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x6280 0x8000 0x7480 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x6780 0x8000 0x7580 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x6D80 0x8000 0x7700 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7500 0x8000 0x7800 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x7A00 0x8000 0x7880 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x8000 0x7980 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7A00 0x7580 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x7480 0x6E80 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x6B00 0x6900 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x6400 0x6380 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x4700 0x8000 0x6800 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x4B80 0x8000 0x6900 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x5000 0x8000 0x6A80 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x5580 0x8000 0x6C00 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x5B00 0x8000 0x6D80 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x6180 0x8000 0x6E80 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x6700 0x8000 0x7080 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x6D00 0x8000 0x7200 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7480 0x8000 0x7400 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x7A00 0x8000 0x7500 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x7F00 0x8000 0x7600 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7A00 0x7080 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x7480 0x6A80 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x6A80 0x6600 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x6380 0x5F80 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x4500 0x8000 0x6400 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x4A00 0x8000 0x6580 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x4F00 0x8000 0x6680 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x5400 0x8000 0x6800 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x5A00 0x8000 0x6900 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x6080 0x8000 0x6A80 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x6600 0x8000 0x6C00 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x6B80 0x8000 0x6D00 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7400 0x8000 0x6E80 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x7980 0x8000 0x7000 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x7F00 0x8000 0x7100 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7A00 0x6C00 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x7400 0x6780 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x6A00 0x6280 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x6300 0x5C00 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x4380 0x8000 0x5F80 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x4880 0x8000 0x6180 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x4D80 0x8000 0x6300 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x5300 0x8000 0x6480 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x5880 0x8000 0x6600 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x5F00 0x8000 0x6700 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x6500 0x8000 0x6880 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x6B00 0x8000 0x6980 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7380 0x8000 0x6A80 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x7900 0x8000 0x6C00 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x7E80 0x8000 0x6D00 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7A00 0x6900 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x7400 0x6480 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x6A00 0x5F00 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x6280 0x5900 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x4180 0x8000 0x5B80 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x4780 0x8000 0x5D80 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x4C00 0x8000 0x5F00 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x5180 0x8000 0x6080 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x5780 0x8000 0x6280 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x5D80 0x8000 0x6400 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x6480 0x8000 0x6580 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x6A80 0x8000 0x6600 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7300 0x8000 0x6780 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x7880 0x8000 0x6900 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x7E80 0x8000 0x6980 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7A00 0x6680 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x7400 0x6180 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x6980 0x5B80 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x6180 0x5700 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-vivid-pcc-enable; + somc,mdss-dsi-vivid-pcc-table-size = <226>; + somc,mdss-dsi-vivid-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x5180 0x6E80 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x5400 0x6E00 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x5680 0x6E00 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x5900 0x6D00 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x5B80 0x6D00 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x5E00 0x6C80 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x6080 0x6C80 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x6300 0x6C80 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x6500 0x6C00 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x6800 0x6C00 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x6A80 0x6C00 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x6D00 0x6B80 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x7000 0x6B80 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x7300 0x6B80 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x7600 0x6B80 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x5600 0x7180 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x5880 0x7100 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x5B00 0x7100 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x5D00 0x7080 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x5F80 0x7080 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x6180 0x7000 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x6380 0x7000 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x6600 0x6F80 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x6880 0x6F80 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x6B00 0x6F00 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x6D80 0x6F00 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x7080 0x6E80 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x7300 0x6E80 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x7600 0x6E80 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x7900 0x6E00 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x5980 0x7480 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x5C00 0x7400 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x5E80 0x7400 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x6080 0x7380 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x6280 0x7300 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x6480 0x7300 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x6700 0x7280 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x6900 0x7200 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x6B80 0x7200 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x6E00 0x7180 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x7080 0x7180 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7380 0x7100 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x7600 0x7100 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x7900 0x7080 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x7C80 0x7080 0x8000 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x5D80 0x7780 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x5F80 0x7700 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x6180 0x7680 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x6380 0x7600 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x6580 0x7600 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x6780 0x7580 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x6A00 0x7500 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x6C00 0x7500 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x6E80 0x7480 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x7100 0x7400 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7380 0x7400 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x7680 0x7380 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x7900 0x7380 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x7C80 0x7300 0x8000 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x7E80 0x7300 0x8000 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x6080 0x7B00 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x6200 0x7A00 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x6400 0x7A00 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x6600 0x7980 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x6800 0x7880 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x6A80 0x7800 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x6C80 0x7780 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x6F00 0x7780 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x7180 0x7700 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7400 0x7680 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x7680 0x7680 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x7900 0x7600 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x7C80 0x7580 0x8000 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x7E80 0x7580 0x8000 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x7480 0x8000 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x6300 0x7D80 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x6500 0x7D00 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x6700 0x7C80 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x6900 0x7C80 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x6B00 0x7C00 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x6D00 0x7B80 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x6F80 0x7B00 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x7180 0x7A80 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7400 0x7A00 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x7680 0x7980 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x7900 0x7880 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x7C80 0x7880 0x8000 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x7E00 0x7800 0x8000 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x7780 0x8000 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x7480 0x7E00 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x6580 0x7F80 0x8000 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x6780 0x7F00 0x8000 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x6980 0x7E80 0x8000 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x6B80 0x7E00 0x8000 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x6D80 0x7E00 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x6F80 0x7D80 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x7200 0x7D00 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7400 0x7C80 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7680 0x7C80 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x7900 0x7C80 0x8000 + 0x00 0x65 0x14 0x16 0x20 0x22 0x7C00 0x7C00 0x8000 + 0x00 0x66 0x11 0x13 0x20 0x22 0x7E00 0x7B80 0x8000 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x7B00 0x8000 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x7780 0x7E80 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x7400 0x7C00 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x6580 0x8000 0x7F00 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x6880 0x8000 0x7F80 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x6B00 0x8000 0x8000 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x6D80 0x8000 0x8000 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x7000 0x8000 0x8000 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x7200 0x7F80 0x8000 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x7480 0x7F00 0x8000 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7680 0x7E80 0x8000 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x7900 0x7E80 0x8000 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x7C00 0x7E00 0x8000 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x7E00 0x7E00 0x8000 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x8000 0x7D80 0x8000 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7B80 0x7F00 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x7700 0x7C80 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x7380 0x7900 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x6500 0x8000 0x7D00 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x6780 0x8000 0x7D80 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x6A00 0x8000 0x7E00 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x6D00 0x8000 0x7E00 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x6F80 0x8000 0x7E80 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x7280 0x8000 0x7F00 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x7580 0x8000 0x7F80 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7880 0x8000 0x8000 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7C00 0x8000 0x8000 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x7E00 0x8000 0x8000 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x7F80 0x7F80 0x8000 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7E00 0x7F00 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7B00 0x7D80 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x7700 0x7A00 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x7380 0x7700 + 0x00 0x88 0x32 0x34 0x17 0x19 0x6400 0x8000 0x7A00 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x6700 0x8000 0x7B80 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x6980 0x8000 0x7C00 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x6C80 0x8000 0x7C80 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x6F00 0x8000 0x7D00 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x7200 0x8000 0x7D80 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x7500 0x8000 0x7E00 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7800 0x8000 0x7E00 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7C00 0x8000 0x7E80 + 0x00 0x91 0x17 0x19 0x17 0x19 0x7E00 0x8000 0x7F00 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x8000 0x7F80 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7E00 0x7D80 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7B00 0x7B80 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x7700 0x7800 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x7300 0x7500 + 0x00 0x97 0x32 0x34 0x14 0x16 0x6300 0x8000 0x7780 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x6600 0x8000 0x7800 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x6900 0x8000 0x7900 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x6B80 0x8000 0x7A00 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x6E80 0x8000 0x7A80 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x7180 0x8000 0x7B80 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x7480 0x8000 0x7C00 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7780 0x8000 0x7C80 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7B00 0x8000 0x7D00 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x7E00 0x8000 0x7D80 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x8000 0x7E00 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7E00 0x7C00 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x7B00 0x7880 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x7680 0x7600 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x7300 0x7300 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x6200 0x8000 0x7580 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x6500 0x8000 0x7600 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x6800 0x8000 0x7680 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x6B00 0x8000 0x7780 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x6E00 0x8000 0x7800 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x7100 0x8000 0x7880 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x7400 0x8000 0x7900 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7780 0x8000 0x7A00 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7B00 0x8000 0x7A80 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x7D80 0x8000 0x7B80 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x8000 0x7C00 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7E00 0x7900 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x7B00 0x7700 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x7680 0x7400 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x7280 0x7180 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x6180 0x8000 0x7380 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x6480 0x8000 0x7400 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x6780 0x8000 0x7480 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x6A80 0x8000 0x7580 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x6D80 0x8000 0x7600 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x7080 0x8000 0x7680 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x7380 0x8000 0x7780 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7700 0x8000 0x7800 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7A80 0x8000 0x7880 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x7D80 0x8000 0x7900 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x8000 0x7A00 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7E00 0x7780 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x7B00 0x7500 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x7680 0x7280 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x7280 0x6F80 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x6080 0x8000 0x7180 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x6380 0x8000 0x7200 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x6680 0x8000 0x7300 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x6980 0x8000 0x7380 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x6D00 0x8000 0x7480 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x7000 0x8000 0x7500 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x7380 0x8000 0x7580 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7680 0x8000 0x7600 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7A80 0x8000 0x7680 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x7D00 0x8000 0x7780 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x7F80 0x8000 0x7800 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7E00 0x7600 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x7B00 0x7380 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x7600 0x7100 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x7200 0x6D80 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x5F80 0x8000 0x6F00 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x6280 0x8000 0x7000 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x6580 0x8000 0x7100 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x6900 0x8000 0x7200 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x6C00 0x8000 0x7280 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x6F80 0x8000 0x7300 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x7300 0x8000 0x7400 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7600 0x8000 0x7480 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7A00 0x8000 0x7500 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x7D00 0x8000 0x7580 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x7F80 0x8000 0x7680 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7E00 0x7480 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x7B00 0x7200 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x7600 0x6F00 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x7180 0x6C80 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-lilac-id8_pcc.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-lilac-id8_pcc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8684538a72221d4df1b0b4defbbf7a984ee826d5 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-lilac-id8_pcc.dtsi @@ -0,0 +1,717 @@ +/* arch/arm64/boot/dts/qcom/dsi-panel-lilac-id8_pcc.dtsi + * + * 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +/* pcc-table for Lilac JDI */ +&mdss_mdp { + dsi_8: somc,8_panel { + somc,mdss-dsi-pcc-enable; + somc,mdss-dsi-uv-command = [ + 06 01 00 00 00 00 01 DA + 06 01 00 00 00 00 01 DB]; + somc,mdss-dsi-uv-param-type = <4>; + somc,mdss-dsi-pcc-table-size = <226>; + somc,mdss-dsi-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x3100 0x5580 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x3380 0x5500 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x3680 0x5480 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x3900 0x5400 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x3B80 0x5380 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x3E00 0x5380 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x4100 0x5380 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x4380 0x5300 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x4700 0x5300 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x4B80 0x5280 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x4F80 0x5200 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x5480 0x5200 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x5980 0x5200 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x5E80 0x5180 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x6300 0x5180 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x3680 0x5C00 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x3900 0x5B80 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x3B80 0x5B00 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x3D80 0x5A80 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x4000 0x5A00 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x4280 0x5980 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x4600 0x5900 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x4980 0x5880 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x4D00 0x5800 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x5180 0x5800 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x5680 0x5780 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x5B00 0x5700 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x6000 0x5700 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x6480 0x5700 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x6900 0x5680 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x3B80 0x6200 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x3D80 0x6180 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x3F80 0x6100 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x4200 0x6080 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x4500 0x6000 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x4800 0x5F00 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x4B80 0x5E80 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x4F80 0x5E80 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x5380 0x5E00 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x5800 0x5D80 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x5C80 0x5D00 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x6100 0x5C80 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x6500 0x5C00 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x6A00 0x5B80 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x6F80 0x5B00 0x8000 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x3F00 0x6780 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x4180 0x6680 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x4380 0x6600 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x4700 0x6580 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x4980 0x6480 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x4D00 0x6400 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x5100 0x6400 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x5580 0x6300 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x5980 0x6280 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x5D80 0x6200 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x6200 0x6180 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x6600 0x6100 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x6A80 0x6100 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x7000 0x6080 0x8000 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x7580 0x6000 0x8000 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x4300 0x6E00 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x4580 0x6C80 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x4880 0x6B80 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x4C00 0x6B00 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x4F00 0x6A80 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x5280 0x6980 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x5700 0x6900 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x5B00 0x6800 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x5F00 0x6700 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x6280 0x6680 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x6700 0x6600 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x6B80 0x6580 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x7080 0x6500 0x8000 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x7600 0x6480 0x8000 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x7B80 0x6400 0x8000 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x4700 0x7480 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x4A00 0x7380 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x4D80 0x7280 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x5080 0x7180 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x5480 0x7080 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x5800 0x6F80 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x5C00 0x6E80 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x6000 0x6D80 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x6380 0x6D00 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x6700 0x6B80 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x6C00 0x6B00 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x7100 0x6A00 0x8000 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x7600 0x6A00 0x8000 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x7B80 0x6900 0x8000 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x6500 0x7A80 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x4C00 0x7B00 0x8000 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x4F00 0x7980 0x8000 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x5200 0x7880 0x8000 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x5600 0x7780 0x8000 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x5980 0x7680 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x5D00 0x7580 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x6100 0x7480 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x6480 0x7380 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x6800 0x7280 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x6C80 0x7180 0x8000 + 0x00 0x65 0x14 0x16 0x20 0x22 0x7200 0x7080 0x8000 + 0x00 0x66 0x11 0x13 0x20 0x22 0x7680 0x7000 0x8000 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x7B80 0x6F00 0x8000 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x6A00 0x7A80 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x6400 0x7500 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x4C80 0x8000 0x7A80 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x5100 0x8000 0x7B80 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x5600 0x8000 0x7E00 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x5A80 0x8000 0x8000 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x5E00 0x7E00 0x8000 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x6180 0x7B80 0x8000 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x6500 0x7A80 0x8000 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x6880 0x7900 0x8000 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x6D00 0x7800 0x8000 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x7280 0x7700 0x8000 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x7680 0x7600 0x8000 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x7B80 0x7500 0x8000 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7080 0x7B00 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x6A00 0x7580 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x6400 0x6F80 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x4B80 0x8000 0x7500 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x4F80 0x8000 0x7600 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x5480 0x8000 0x7780 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x5980 0x8000 0x7880 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x5E00 0x8000 0x7980 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x6280 0x8000 0x7B00 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x6700 0x8000 0x7C00 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x6C80 0x8000 0x7E00 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7280 0x8000 0x8000 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x7700 0x7E00 0x8000 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x8000 0x8000 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7680 0x7B00 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7000 0x7600 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x6980 0x6F80 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x6300 0x6A80 + 0x00 0x88 0x32 0x34 0x17 0x19 0x4A00 0x8000 0x6F00 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x4E80 0x8000 0x7000 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x5380 0x8000 0x7180 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x5800 0x8000 0x7380 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x5D00 0x8000 0x7480 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x6200 0x8000 0x7600 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x6680 0x8000 0x7700 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x6B80 0x8000 0x7800 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7200 0x8000 0x7900 + 0x00 0x91 0x17 0x19 0x17 0x19 0x7700 0x8000 0x7A00 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x8000 0x7B00 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7680 0x7680 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7000 0x7100 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x6900 0x6B80 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x6280 0x6700 + 0x00 0x97 0x32 0x34 0x14 0x16 0x4900 0x8000 0x6A00 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x4D00 0x8000 0x6B80 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x5200 0x8000 0x6D00 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x5780 0x8000 0x6E00 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x5C80 0x8000 0x6F80 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x6100 0x8000 0x7000 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x6600 0x8000 0x7200 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x6B00 0x8000 0x7380 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7100 0x8000 0x7480 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x7700 0x8000 0x7580 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x8000 0x7700 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7680 0x7200 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x6F80 0x6C80 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x6880 0x6800 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x6200 0x6300 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x4700 0x8000 0x6600 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x4C00 0x8000 0x6780 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x5100 0x8000 0x6880 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x5680 0x8000 0x6A00 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x5B80 0x8000 0x6B00 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x6100 0x8000 0x6C00 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x6500 0x8000 0x6D80 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x6A80 0x8000 0x6E80 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7080 0x8000 0x7000 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x7680 0x8000 0x7100 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x8000 0x7200 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7680 0x6D80 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x6F80 0x6900 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x6800 0x6480 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x6180 0x5F80 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x4600 0x8000 0x6280 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x4A80 0x8000 0x6400 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x4F80 0x8000 0x6500 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x5500 0x8000 0x6600 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x5A80 0x8000 0x6780 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x6000 0x8000 0x6880 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x6500 0x8000 0x6980 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x6A00 0x8000 0x6A80 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7000 0x8000 0x6C00 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x7680 0x8000 0x6D00 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x7E00 0x8000 0x6E00 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7680 0x6A00 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x6F80 0x6600 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x6780 0x6180 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x6100 0x5C00 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x4500 0x8000 0x5E80 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x4980 0x8000 0x5F80 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x4E80 0x8000 0x6100 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x5400 0x8000 0x6300 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x5980 0x8000 0x6400 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x5F00 0x8000 0x6580 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x6400 0x8000 0x6600 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x6980 0x8000 0x6780 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x6F80 0x8000 0x6880 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x7600 0x8000 0x6980 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x7E00 0x8000 0x6A80 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7680 0x6700 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x6F00 0x6300 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x6700 0x5E00 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x6080 0x5900 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x4380 0x8000 0x5A80 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x4800 0x8000 0x5C00 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x4D00 0x8000 0x5D80 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x5280 0x8000 0x5F00 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x5880 0x8000 0x6080 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x5E00 0x8000 0x6200 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x6380 0x8000 0x6380 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x6900 0x8000 0x6480 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x6F00 0x8000 0x6580 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x7580 0x8000 0x6680 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x7E00 0x8000 0x6780 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7680 0x6480 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x6F00 0x5F80 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x6680 0x5B00 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x6000 0x5600 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-srgb-pcc-enable; + somc,mdss-dsi-srgb-pcc-table-size = <226>; + somc,mdss-dsi-srgb-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x3080 0x5600 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x3300 0x5580 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x3580 0x5500 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x3880 0x5500 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x3B80 0x5480 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x3E00 0x5480 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x4100 0x5400 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x4480 0x5380 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x4780 0x5380 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x4B80 0x5300 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x5000 0x5300 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x5480 0x5280 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x5980 0x5300 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x5F00 0x5280 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x6400 0x5280 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x3580 0x5D00 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x3880 0x5C80 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x3B00 0x5B80 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x3D80 0x5B00 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x4080 0x5A80 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x4300 0x5A00 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x4600 0x5980 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x4A00 0x5900 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x4D80 0x5880 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x5200 0x5880 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x5680 0x5800 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x5B80 0x5800 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x6000 0x5780 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x6500 0x5780 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x6980 0x5700 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x3B00 0x6300 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x3D80 0x6280 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x3F80 0x6200 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x4200 0x6180 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x4500 0x6080 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x4800 0x6000 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x4C00 0x5F80 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x4F80 0x5F00 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x5400 0x5F00 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x5800 0x5E80 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x5D00 0x5E00 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x6180 0x5D80 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x6600 0x5D00 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x6A80 0x5C80 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x7000 0x5C00 0x8000 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x3F80 0x6880 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x4200 0x6780 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x4480 0x6700 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x4700 0x6680 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x4A00 0x6600 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x4D80 0x6580 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x5100 0x6480 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x5500 0x6400 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x5980 0x6380 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x5E00 0x6300 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x6280 0x6280 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x6680 0x6200 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x6B00 0x6180 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x7080 0x6180 0x8000 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x7600 0x6100 0x8000 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x4380 0x6E80 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x4600 0x6D80 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x4900 0x6C80 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x4C00 0x6B80 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x4F80 0x6A80 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x5300 0x6A00 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x5700 0x6980 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x5B00 0x6880 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x5F00 0x6800 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x6380 0x6780 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x6780 0x6700 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x6B80 0x6680 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x7100 0x6600 0x8000 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x7680 0x6580 0x8000 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x7B80 0x6500 0x8000 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x4780 0x7500 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x4A80 0x7400 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x4D80 0x7300 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x5100 0x7200 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x5480 0x7100 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x5880 0x7000 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x5C80 0x6F80 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x6080 0x6E00 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x6480 0x6D00 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x6800 0x6C80 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x6C00 0x6B80 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x7180 0x6A80 0x8000 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x7680 0x6A00 0x8000 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x7B80 0x6A00 0x8000 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x6580 0x7900 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x4C80 0x7B00 0x8000 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x4F80 0x7A00 0x8000 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x5280 0x7900 0x8000 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x5600 0x7780 0x8000 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x5A00 0x7700 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x5D80 0x7600 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x6180 0x7500 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x6500 0x7400 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x6880 0x7300 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x6D00 0x7200 0x8000 + 0x00 0x65 0x14 0x16 0x20 0x22 0x7200 0x7180 0x8000 + 0x00 0x66 0x11 0x13 0x20 0x22 0x7700 0x7080 0x8000 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x7B80 0x6F80 0x8000 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x6A80 0x7980 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x6580 0x7380 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x4D80 0x8000 0x7980 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x5100 0x8000 0x7A80 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x5580 0x8000 0x7C00 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x5A80 0x8000 0x8000 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x5E80 0x7E00 0x8000 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x6200 0x7B80 0x8000 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x6600 0x7A80 0x8000 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x6900 0x7980 0x8000 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x6D80 0x7880 0x8000 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x7280 0x7780 0x8000 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x7700 0x7680 0x8000 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x7B80 0x7580 0x8000 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7100 0x7980 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x6A00 0x7400 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x6480 0x6D80 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x4C00 0x8000 0x7380 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x5080 0x8000 0x7500 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x5480 0x8000 0x7600 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x5980 0x8000 0x7780 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x5E80 0x8000 0x7880 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x6300 0x8000 0x7980 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x6780 0x8000 0x7B00 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x6C00 0x8000 0x7C00 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7280 0x8000 0x8000 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x7780 0x7E00 0x8000 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x8000 0x8000 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7700 0x7A00 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7100 0x7480 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x6980 0x6E80 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x6400 0x6900 + 0x00 0x88 0x32 0x34 0x17 0x19 0x4A80 0x8000 0x6D80 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x4F00 0x8000 0x6F80 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x5380 0x8000 0x7080 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x5880 0x8000 0x7200 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x5D80 0x8000 0x7380 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x6280 0x8000 0x7480 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x6700 0x8000 0x7580 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x6B80 0x8000 0x7700 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7200 0x8000 0x7800 + 0x00 0x91 0x17 0x19 0x17 0x19 0x7780 0x8000 0x7900 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x8000 0x7A00 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7700 0x7500 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7080 0x7000 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x6980 0x6A80 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x6400 0x6580 + 0x00 0x97 0x32 0x34 0x14 0x16 0x4900 0x8000 0x6880 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x4D80 0x8000 0x6A00 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x5280 0x8000 0x6B80 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x5780 0x8000 0x6C80 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x5D00 0x8000 0x6E00 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x6180 0x8000 0x6F80 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x6680 0x8000 0x7100 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x6B80 0x8000 0x7200 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7180 0x8000 0x7300 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x7780 0x8000 0x7480 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x8000 0x7580 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7700 0x7100 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x7080 0x6B00 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x6900 0x6700 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x6300 0x6200 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x4780 0x8000 0x6500 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x4C80 0x8000 0x6600 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x5100 0x8000 0x6700 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x5680 0x8000 0x6800 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x5C00 0x8000 0x6980 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x6100 0x8000 0x6B00 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x6600 0x8000 0x6B80 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x6B00 0x8000 0x6D00 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7100 0x8000 0x6E00 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x7700 0x8000 0x7000 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x8000 0x7100 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7700 0x6C00 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x7000 0x6780 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x6900 0x6380 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x6280 0x5E00 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x4680 0x8000 0x6100 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x4B00 0x8000 0x6200 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x5080 0x8000 0x6400 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x5500 0x8000 0x6500 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x5B00 0x8000 0x6600 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x6080 0x8000 0x6700 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x6580 0x8000 0x6800 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x6A80 0x8000 0x6900 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7080 0x8000 0x6A80 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x7700 0x8000 0x6B80 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x7E00 0x8000 0x6C80 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7700 0x6880 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x7000 0x6480 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x6880 0x6000 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x6200 0x5A80 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x4500 0x8000 0x5C80 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x4A00 0x8000 0x5E00 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x4F00 0x8000 0x6000 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x5480 0x8000 0x6100 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x5A00 0x8000 0x6280 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x5F80 0x8000 0x6400 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x6480 0x8000 0x6500 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x6A00 0x8000 0x6600 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7000 0x8000 0x6700 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x7680 0x8000 0x6800 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x7E00 0x8000 0x6900 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7700 0x6580 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x6F80 0x6180 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x6800 0x5C80 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x6180 0x5700 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x4400 0x8000 0x5880 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x4880 0x8000 0x5A80 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x4D80 0x8000 0x5C00 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x5300 0x8000 0x5D80 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x5900 0x8000 0x5F00 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x5E80 0x8000 0x6080 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x6400 0x8000 0x6180 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x6900 0x8000 0x6300 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x6F80 0x8000 0x6400 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x7600 0x8000 0x6580 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x7E00 0x8000 0x6600 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7700 0x6300 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x6F80 0x5E80 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x6780 0x5900 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x6080 0x5480 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-vivid-pcc-enable; + somc,mdss-dsi-vivid-pcc-table-size = <226>; + somc,mdss-dsi-vivid-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x5380 0x6D00 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x5600 0x6C80 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x5800 0x6C80 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x5A00 0x6C80 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x5B80 0x6C00 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x5D80 0x6C00 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x5F80 0x6C00 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x6180 0x6B80 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x6400 0x6B80 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x6600 0x6B80 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x6880 0x6B80 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x6B80 0x6B00 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x6E00 0x6B00 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x7180 0x6B00 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x7380 0x6B00 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x5800 0x7080 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x5A00 0x7000 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x5B80 0x6F80 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x5D80 0x6F80 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x5F00 0x6F00 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x6100 0x6F00 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x6300 0x6F00 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x6500 0x6E80 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x6780 0x6E80 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x6A00 0x6E00 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x6C80 0x6E00 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x6F00 0x6E00 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x7180 0x6D80 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x7400 0x6D80 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x7680 0x6D80 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x5B80 0x7400 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x5D00 0x7380 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x5E80 0x7300 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x6080 0x7280 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x6280 0x7200 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x6480 0x7200 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x6680 0x7180 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x6880 0x7180 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x6B00 0x7100 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x6D80 0x7100 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x7080 0x7080 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7200 0x7080 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x7500 0x7080 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x7700 0x7000 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x7980 0x7000 0x8000 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x5E80 0x7680 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x6000 0x7600 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x6200 0x7580 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x6380 0x7580 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x6580 0x7500 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x6780 0x7480 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x6A00 0x7480 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x6C00 0x7400 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x6E00 0x7380 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x7100 0x7400 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7300 0x7380 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x7580 0x7300 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x7780 0x7300 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x7A80 0x7280 0x8000 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x7C80 0x7200 0x8000 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x6180 0x7980 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x6300 0x7900 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x6480 0x7880 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x6680 0x7800 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x6880 0x7780 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x6B00 0x7780 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x6D00 0x7700 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x6F00 0x7680 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x7180 0x7680 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7380 0x7600 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x7580 0x7580 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x7780 0x7580 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x7A00 0x7500 0x8000 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x7C80 0x7500 0x8000 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x7F80 0x7480 0x8000 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x6400 0x7C80 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x6580 0x7C00 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x6780 0x7B80 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x6A00 0x7B80 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x6B80 0x7A80 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x6D80 0x7A00 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x7000 0x7980 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x7180 0x7900 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7400 0x7900 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x7600 0x7880 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x7800 0x7800 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x7B00 0x7780 0x8000 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x7D00 0x7780 0x8000 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x7F80 0x7700 0x8000 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x7500 0x7E80 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x6680 0x7F80 0x8000 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x6880 0x7F00 0x8000 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x6A80 0x7E80 0x8000 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x6C80 0x7E00 0x8000 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x6E80 0x7D80 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x7080 0x7D00 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x7200 0x7C80 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7480 0x7C00 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7680 0x7B80 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x7800 0x7B80 0x8000 + 0x00 0x65 0x14 0x16 0x20 0x22 0x7B00 0x7A80 0x8000 + 0x00 0x66 0x11 0x13 0x20 0x22 0x7D00 0x7A00 0x8000 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x7F80 0x7980 0x8000 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x7780 0x7E80 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x7480 0x7C00 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x6700 0x8000 0x7E80 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x6A00 0x8000 0x7F00 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x6C80 0x8000 0x7F80 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x6E80 0x8000 0x8000 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x7180 0x8000 0x8000 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x7280 0x7F80 0x8000 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x7500 0x7F00 0x8000 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7680 0x7E80 0x8000 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x7880 0x7E00 0x8000 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x7B00 0x7D80 0x8000 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x7D00 0x7D00 0x8000 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x7F80 0x7D00 0x8000 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7A80 0x7E80 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x7780 0x7C80 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x7480 0x7980 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x6680 0x8000 0x7C00 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x6900 0x8000 0x7C80 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x6B80 0x8000 0x7D00 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x6E00 0x8000 0x7D80 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x7100 0x8000 0x7E80 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x7380 0x8000 0x7E80 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x7600 0x8000 0x7F00 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7800 0x8000 0x7F80 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7B80 0x8000 0x8000 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x7D00 0x8000 0x8000 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x7F80 0x7F80 0x8000 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7D80 0x7F00 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7A80 0x7C80 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x7780 0x7A00 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x7400 0x7700 + 0x00 0x88 0x32 0x34 0x17 0x19 0x6580 0x8000 0x7900 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x6800 0x8000 0x7A00 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x6B00 0x8000 0x7B00 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x6D80 0x8000 0x7B80 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x7100 0x8000 0x7C00 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x7300 0x8000 0x7C80 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x7580 0x8000 0x7D00 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7800 0x8000 0x7D80 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7B00 0x8000 0x7E00 + 0x00 0x91 0x17 0x19 0x17 0x19 0x7D80 0x8000 0x7E80 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x8000 0x7F00 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7D80 0x7D00 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7A00 0x7A00 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x7700 0x7780 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x7400 0x7500 + 0x00 0x97 0x32 0x34 0x14 0x16 0x6500 0x8000 0x7700 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x6780 0x8000 0x7780 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x6A80 0x8000 0x7800 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x6D00 0x8000 0x7900 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x7080 0x8000 0x7980 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x7280 0x8000 0x7A00 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x7580 0x8000 0x7A80 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7780 0x8000 0x7B80 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7B00 0x8000 0x7C00 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x7D00 0x8000 0x7C80 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x8000 0x7D00 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7D80 0x7B00 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x7A00 0x7800 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x7700 0x7600 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x7400 0x7380 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x6400 0x8000 0x7500 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x6680 0x8000 0x7580 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x6A00 0x8000 0x7600 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x6C80 0x8000 0x7700 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x7000 0x8000 0x7780 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x7200 0x8000 0x7800 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x7500 0x8000 0x7800 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7780 0x8000 0x7900 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7A80 0x8000 0x7980 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x7D00 0x8000 0x7A00 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x8000 0x7B00 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7D80 0x7880 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x7A00 0x7680 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x7680 0x7400 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x7380 0x7180 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x6380 0x8000 0x7280 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x6600 0x8000 0x7380 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x6880 0x8000 0x7400 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x6C00 0x8000 0x7500 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x6F00 0x8000 0x7580 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x7180 0x8000 0x7600 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x7480 0x8000 0x7680 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7700 0x8000 0x7700 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7A00 0x8000 0x7800 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x7D00 0x8000 0x7880 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x8000 0x7900 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7D80 0x7700 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x7A00 0x7480 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x7680 0x7280 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x7300 0x6F80 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x6280 0x8000 0x7080 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x6500 0x8000 0x7180 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x6800 0x8000 0x7200 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x6B80 0x8000 0x7300 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x6E80 0x8000 0x7380 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x7180 0x8000 0x7480 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x7400 0x8000 0x7500 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7680 0x8000 0x7580 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7980 0x8000 0x7600 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x7D00 0x8000 0x7680 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x8000 0x8000 0x7700 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7D80 0x7580 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x7980 0x7300 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x7600 0x7080 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x7300 0x6E00 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x6180 0x8000 0x6F00 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x6480 0x8000 0x6F80 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x6780 0x8000 0x7080 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x6B00 0x8000 0x7100 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x6E00 0x8000 0x7200 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x7180 0x8000 0x7280 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x7400 0x8000 0x7300 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7680 0x8000 0x7400 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7980 0x8000 0x7480 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x7C80 0x8000 0x7500 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x8000 0x8000 0x7580 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7D80 0x7400 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x7980 0x7180 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x7600 0x6F00 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x7200 0x6C00 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-lilac.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-lilac.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..77e9bfae880cda3816a0b09d885609f1feb407b1 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-lilac.dtsi @@ -0,0 +1,640 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include "dsi-panel-lilac-id5_pcc.dtsi" +#include "dsi-panel-lilac-id8_pcc.dtsi" + +&mdss_mdp { + /* LGD ID5 */ + dsi_5: somc,5_panel { + qcom,mdss-dsi-panel-name = "5"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-front-porch = <280>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-v-front-porch = <1162>; + qcom,mdss-pan-physical-width-dimension = <56>; + qcom,mdss-pan-physical-height-dimension = <100>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-underflow-color = <0x0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-on-command = [ + 23 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 20 C1 84 01 10 FF D3 29 E3 3B 66 D5 EF 1A 63 CD FD BA CC 01 62 90 F2 3F 00 AA 40 02 C2 11 08 00 01 + 29 01 00 00 00 00 0A CB FC F7 FB 0F 00 00 00 00 00 + 39 01 00 00 00 00 05 2A 00 00 02 CF + 39 01 00 00 00 00 05 2B 00 00 04 FF + 05 01 00 00 64 00 01 11]; + qcom,mdss-dsi-post-panel-on-command = [ + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 01 28 + 05 01 00 00 64 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [00 1E 06 06 0E 0F 07 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x2C>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_full_incell>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14940 15790 33800 15700 10950 33800 7450 2300>; + qcom,mdss-dsi-panel-peak-brightness = <7000000>; + qcom,mdss-dsi-panel-blackness-level = <4646>; + + qcom,mdss-dsi-panel-clockrate = <899000000>; + + somc,lcd-id-adc = <801000 917000>; + somc,mdss-dsi-master; + somc,pw-on-rst-seq = <0 15>, <1 20>; + somc,pw-off-rst-b-seq = <0 11>; + somc,pw-wait-after-on-vdd = <0>; + somc,pw-wait-after-on-vddio = <0>; + somc,pw-wait-after-on-vsp = <8>; + somc,pw-wait-after-on-vsn = <0>; + somc,pw-wait-after-off-vdd = <0>; + somc,pw-wait-after-off-vddio = <1>; + somc,pw-wait-after-off-vsp = <8>; + somc,pw-wait-after-off-vsn = <8>; + somc,pw-wait-after-on-touch-vddio = <0>; + somc,pw-wait-after-on-touch-reset = <0>; + somc,pw-wait-after-on-touch-int-n = <10>; + somc,pw-wait-after-off-touch-vddio = <0>; + somc,pw-wait-after-off-touch-reset = <11>; + somc,pw-wait-after-off-touch-int-n = <0>; + somc,pw-down-period = <300>; + + somc,lab-output-voltage = <5500000>; + somc,ibb-output-voltage = <5500000>; + somc,qpnp-lab-limit-maximum-current = <200>; + somc,qpnp-ibb-limit-maximum-current = <800>; + somc,qpnp-lab-max-precharge-time = <500>; + somc,qpnp-lab-soft-start = <800>; + somc,qpnp-ibb-discharge-resistor = <300>; + somc,qpnp-lab-pull-down-enable; + somc,qpnp-lab-full-pull-down; + somc,qpnp-ibb-pull-down-enable; + somc,qpnp-ibb-full-pull-down; + + somc,ewu-rst-seq = <0 2>, <1 5>; + somc,ewu-wait-after-touch-reset = <0>; + + somc,change-fps-enable; + somc,change-fps-panel-type = "full_incell_type"; + somc,change-fps-panel-mode = "dynamic_mode"; + somc,change-fps-command = + [29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 02 C6 59]; + somc,driver-ic-total-porch = <11>; + somc,driver-ic-vdisp = <1280>; + somc,driver-ic-rclk = <14000000>; + somc,driver-ic-vtp = <1330>; + somc,change-fps-rtn-pos = <2 1>; + + somc,mdss-dsi-disp-on-in-hs = <0>; + somc,mdss-dsi-wait-time-before-post-on-cmd = <0>; + }; + + /* Kugo AUO ID6 */ + dsi_6: somc,6_panel { + qcom,mdss-dsi-panel-name = "6"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-front-porch = <280>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-v-front-porch = <1162>; + qcom,mdss-pan-physical-width-dimension = <56>; + qcom,mdss-pan-physical-height-dimension = <100>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-underflow-color = <0x0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 20 C1 84 01 00 FF 47 99 80 39 EB FF CF 9A 73 8D FD BF D6 31 2F 89 F1 3F 00 00 40 22 82 03 08 00 01 + 29 01 00 00 00 00 0F C6 7A 02 7A 05 78 01 64 01 02 01 02 0B 1C 07 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2A 00 00 02 CF + 39 01 00 00 00 00 05 2B 00 00 04 FF + 05 01 00 00 78 00 01 11]; + qcom,mdss-dsi-post-panel-on-command = [ + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 28 00 01 28 + 29 01 00 00 00 00 1D D3 13 3B BB B3 A5 33 33 33 00 80 A1 AA 4F 4F 33 33 33 F7 F2 0F 7D 7C FF 0F 99 00 FF FF + 29 01 00 00 28 00 04 D4 00 00 00 + 05 01 00 00 78 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [00 1E 06 06 0E 0F 07 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x2C>; + + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_full_incell>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14940 15790 33800 15700 10950 33800 7450 2300>; + qcom,mdss-dsi-panel-peak-brightness = <7000000>; + qcom,mdss-dsi-panel-blackness-level = <4646>; + + qcom,mdss-dsi-panel-clockrate = <899000000>; + + somc,lcd-id-adc = <565000 653000>; + somc,mdss-dsi-master; + somc,pw-on-rst-seq = <0 10>, <1 10>; + somc,pw-off-rst-seq = <0 0>; + somc,pw-wait-after-on-vdd = <0>; + somc,pw-wait-after-on-vddio = <1>; + somc,pw-wait-after-on-vsp = <1>; + somc,pw-wait-after-on-vsn = <20>; + somc,pw-wait-after-off-vdd = <0>; + somc,pw-wait-after-off-vddio = <0>; + somc,pw-wait-after-off-vsp = <70>; + somc,pw-wait-after-off-vsn = <0>; + somc,pw-wait-after-on-touch-avdd = <1>; + somc,pw-wait-after-on-touch-vddio = <0>; + somc,pw-wait-after-on-touch-reset = <0>; + somc,pw-wait-after-on-touch-int-n = <10>; + somc,pw-wait-after-off-touch-avdd = <0>; + somc,pw-wait-after-off-touch-vddio = <0>; + somc,pw-wait-after-off-touch-reset = <11>; + somc,pw-wait-after-off-touch-int-n = <0>; + somc,pw-down-period = <100>; + + somc,lab-output-voltage = <5600000>; + somc,ibb-output-voltage = <5600000>; + somc,qpnp-lab-limit-maximum-current = <200>; + somc,qpnp-ibb-limit-maximum-current = <800>; + somc,qpnp-lab-max-precharge-time = <500>; + somc,qpnp-lab-soft-start = <800>; + somc,qpnp-ibb-discharge-resistor = <300>; + somc,qpnp-lab-pull-down-enable; + somc,qpnp-lab-full-pull-down; + somc,qpnp-ibb-pull-down-enable; + somc,qpnp-ibb-full-pull-down; + + + somc,ewu-wait-after-touch-reset = <40>; + + somc,mdss-dsi-disp-on-in-hs = <0>; + somc,mdss-dsi-wait-time-before-post-on-cmd = <0>; + }; + + /* JDI ID8 */ + dsi_8: somc,8_panel { + qcom,mdss-dsi-panel-name = "8"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-front-porch = <280>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-v-front-porch = <1162>; + qcom,mdss-pan-physical-width-dimension = <56>; + qcom,mdss-pan-physical-height-dimension = <100>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-underflow-color = <0x0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 08 C2 01 05 00 04 00 04 F0 + 29 01 00 00 00 00 0E EC 64 DC 7A 7A 3D 00 0B 0B 13 15 68 0B B5 + 29 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 36 00 + 39 01 00 00 00 00 02 3A 77 + 39 01 00 00 00 00 05 2A 00 00 02 CF + 39 01 00 00 00 00 05 2B 00 00 04 FF + 39 01 00 00 00 00 03 44 00 00 + 39 01 00 00 78 00 01 11]; + qcom,mdss-dsi-post-panel-on-command = [ + 39 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = [ + 39 01 00 00 00 00 01 28 + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 0E EC 64 DC 7A 7A 3D 00 0B 0B 13 15 68 0B 95 + 29 01 00 00 00 00 02 B0 03 + 39 01 00 00 78 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [00 1E 06 06 0E 0F 07 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x2C>; + + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_hybrid_incell>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14940 15790 33800 15700 10950 33800 7450 2300>; + qcom,mdss-dsi-panel-peak-brightness = <7000000>; + qcom,mdss-dsi-panel-blackness-level = <4646>; + + qcom,mdss-dsi-panel-clockrate = <899000000>; + + somc,lcd-id-adc = <215000 256000>; + somc,mdss-dsi-master; + somc,pw-on-rst-seq = <0 15>, <1 16>, <0 15>, <1 20>; + somc,pw-off-rst-b-seq = <0 11>; + somc,pw-wait-after-on-vdd = <0>; + somc,pw-wait-after-on-vddio = <1>; + somc,pw-wait-after-on-vsp = <1>; + somc,pw-wait-after-on-vsn = <0>; + somc,pw-wait-after-off-vdd = <0>; + somc,pw-wait-after-off-vddio = <1>; + somc,pw-wait-after-off-vsp = <8>; + somc,pw-wait-after-off-vsn = <8>; + somc,pw-wait-after-on-touch-avdd = <1>; + somc,pw-wait-after-on-touch-vddio = <0>; + somc,pw-wait-after-on-touch-reset = <0>; + somc,pw-wait-after-on-touch-int-n = <10>; + somc,pw-wait-after-off-touch-avdd = <0>; + somc,pw-wait-after-off-touch-vddio = <0>; + somc,pw-wait-after-off-touch-reset = <11>; + somc,pw-wait-after-off-touch-int-n = <0>; + somc,pw-down-period = <300>; + + somc,lab-output-voltage = <5600000>; + somc,ibb-output-voltage = <5600000>; + somc,qpnp-lab-limit-maximum-current = <200>; + somc,qpnp-ibb-limit-maximum-current = <800>; + somc,qpnp-lab-max-precharge-time = <500>; + somc,qpnp-lab-soft-start = <800>; + somc,qpnp-ibb-discharge-resistor = <300>; + somc,qpnp-lab-pull-down-enable; + somc,qpnp-lab-full-pull-down; + somc,qpnp-ibb-pull-down-enable; + somc,qpnp-ibb-full-pull-down; + + somc,ewu-wait-after-touch-reset = <40>; + + somc,change-fps-enable; + somc,change-fps-panel-type = "hybrid_incell_type"; + somc,change-fps-panel-mode = "dynamic_mode"; + somc,change-fps-command = + [29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 08 C2 01 05 00 04 00 04 F0]; + somc,driver-ic-rtn = <122>; + somc,driver-ic-vdisp = <1280>; + somc,driver-ic-vtouch = <6993970>; + somc,driver-ic-mclk = <61539>; + somc,change-fps-send-pos = <2 4>; + somc,change-fps-send-byte = <4>; + somc,change-fps-porch-mask-pos = <3>; + somc,change-fps-porch-mask = <0xF0>; + somc,change-fps-porch-range = <4 511>; + + somc,mdss-dsi-disp-on-in-hs = <0>; + somc,mdss-dsi-wait-time-before-post-on-cmd = <0>; + }; + + /* Kagura Sharp ID9 */ + dsi_9: somc,9_panel { + qcom,mdss-dsi-panel-name = "9"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-front-porch = <280>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-v-front-porch = <1162>; + qcom,mdss-pan-physical-width-dimension = <56>; + qcom,mdss-pan-physical-height-dimension = <100>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-underflow-color = <0x0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2A 00 00 02 CF + 39 01 00 00 00 00 05 2B 00 00 04 FF + 05 01 00 00 78 00 01 29]; + qcom,mdss-dsi-post-panel-on-command = [ + 05 01 00 00 00 00 01 11]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 01 28 + 05 01 00 00 78 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [00 1E 06 06 0E 0F 07 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x2C>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_full_incell>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14940 15790 33800 15700 10950 33800 7450 2300>; + qcom,mdss-dsi-panel-peak-brightness = <7000000>; + qcom,mdss-dsi-panel-blackness-level = <4646>; + + qcom,mdss-dsi-panel-clockrate = <899000000>; + + somc,lcd-id-adc = <0 57000>; + somc,mdss-dsi-master; + somc,pw-on-rst-seq = <0 10>, <1 10>; + somc,pw-off-rst-b-seq = <0 5>; + somc,pw-wait-after-on-vdd = <0>; + somc,pw-wait-after-on-vddio = <10>; + somc,pw-wait-after-on-vsp = <10>; + somc,pw-wait-after-on-vsn = <0>; + somc,pw-wait-after-off-vdd = <0>; + somc,pw-wait-after-off-vddio = <0>; + somc,pw-wait-after-off-vsp = <10>; + somc,pw-wait-after-off-vsn = <10>; + somc,pw-wait-after-on-touch-vddio = <0>; + somc,pw-wait-after-on-touch-reset = <0>; + somc,pw-wait-after-on-touch-int-n = <10>; + somc,pw-wait-after-off-touch-vddio = <0>; + somc,pw-wait-after-off-touch-reset = <6>; + somc,pw-wait-after-off-touch-int-n = <0>; + somc,pw-down-period = <300>; + + somc,lab-output-voltage = <5600000>; + somc,ibb-output-voltage = <5600000>; + somc,qpnp-lab-limit-maximum-current = <200>; + somc,qpnp-ibb-limit-maximum-current = <800>; + somc,qpnp-lab-max-precharge-time = <500>; + somc,qpnp-lab-soft-start = <800>; + somc,qpnp-ibb-discharge-resistor = <300>; + somc,qpnp-lab-pull-down-enable; + somc,qpnp-lab-full-pull-down; + somc,qpnp-ibb-pull-down-enable; + somc,qpnp-ibb-full-pull-down; + + somc,ewu-rst-seq = <0 2>, <1 5>; + somc,ewu-wait-after-touch-reset = <0>; + }; + + /* Default */ + dsi_default_panel: somc,default_cmd_panel { + qcom,mdss-dsi-panel-name = "default"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-front-porch = <280>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-v-front-porch = <1162>; + qcom,mdss-pan-physical-width-dimension = <56>; + qcom,mdss-pan-physical-height-dimension = <100>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-underflow-color = <0x0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 08 C2 01 05 00 04 00 04 F0 + 29 01 00 00 00 00 0E EC 64 DC 7A 7A 3D 00 0B 0B 13 15 68 0B B5 + 29 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 36 00 + 39 01 00 00 00 00 02 3A 77 + 39 01 00 00 00 00 05 2A 00 00 02 CF + 39 01 00 00 00 00 05 2B 00 00 04 FF + 39 01 00 00 00 00 03 44 00 00 + 39 01 00 00 78 00 01 11]; + qcom,mdss-dsi-post-panel-on-command = [ + 39 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = [ + 39 01 00 00 00 00 01 28 + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 0E EC 64 DC 7A 7A 3D 00 0B 0B 13 15 68 0B 95 + 29 01 00 00 00 00 02 B0 03 + 39 01 00 00 78 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [00 1E 06 06 0E 0F 07 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x2C>; + + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_hybrid_incell>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14940 15790 33800 15700 10950 33800 7450 2300>; + qcom,mdss-dsi-panel-peak-brightness = <7000000>; + qcom,mdss-dsi-panel-blackness-level = <4646>; + + qcom,mdss-dsi-panel-clockrate = <899000000>; + + somc,lcd-id-adc = <0 0x7fffffff>; + somc,mdss-dsi-master; + somc,pw-on-rst-seq = <0 15>, <1 16>, <0 15>, <1 20>; + somc,pw-off-rst-b-seq = <0 11>; + somc,pw-wait-after-on-vdd = <0>; + somc,pw-wait-after-on-vddio = <1>; + somc,pw-wait-after-on-vsp = <1>; + somc,pw-wait-after-on-vsn = <0>; + somc,pw-wait-after-off-vdd = <0>; + somc,pw-wait-after-off-vddio = <1>; + somc,pw-wait-after-off-vsp = <8>; + somc,pw-wait-after-off-vsn = <8>; + somc,pw-wait-after-on-touch-avdd = <1>; + somc,pw-wait-after-on-touch-vddio = <0>; + somc,pw-wait-after-on-touch-reset = <0>; + somc,pw-wait-after-on-touch-int-n = <10>; + somc,pw-wait-after-off-touch-avdd = <0>; + somc,pw-wait-after-off-touch-vddio = <0>; + somc,pw-wait-after-off-touch-reset = <11>; + somc,pw-wait-after-off-touch-int-n = <0>; + somc,pw-down-period = <300>; + + somc,lab-output-voltage = <5600000>; + somc,ibb-output-voltage = <5600000>; + somc,qpnp-lab-limit-maximum-current = <200>; + somc,qpnp-ibb-limit-maximum-current = <800>; + somc,qpnp-lab-max-precharge-time = <500>; + somc,qpnp-lab-soft-start = <800>; + somc,qpnp-ibb-discharge-resistor = <300>; + somc,qpnp-lab-pull-down-enable; + somc,qpnp-lab-full-pull-down; + somc,qpnp-ibb-pull-down-enable; + somc,qpnp-ibb-full-pull-down; + + somc,ewu-wait-after-touch-reset = <40>; + + somc,mdss-dsi-disp-on-in-hs = <0>; + somc,mdss-dsi-wait-time-before-post-on-cmd = <0>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi index aa627b3e7c63caff13bf7fc1be51ee6968e6e19c..5971a3d1025e6579e6031352f350af5e7cc3f939 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi @@ -68,6 +68,7 @@ qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; qcom,mdss-dsi-lane-3-state; + qcom,cmd-sync-wait-broadcast; qcom,mdss-dsi-panel-timings = [e2 36 24 00 66 6a 28 38 2a 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi index 339d87f66d2fc78e4eb70d714763842a9836c541..1a572f97c840618d075b8e67322a09c9fa3bfb01 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -193,6 +193,7 @@ qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; qcom,mdss-dsi-lane-3-state; + qcom,cmd-sync-wait-broadcast; qcom,mdss-dsi-panel-timings = [e2 36 24 00 66 6a 28 38 2a 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x0d>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-poplar-id6_pcc.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-poplar-id6_pcc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e34764a0fd65e61c120b3eb9e23beb985f36dd20 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-poplar-id6_pcc.dtsi @@ -0,0 +1,947 @@ +/* arch/arm64/boot/dts/qcom/dsi-panel-poplar-id6_pcc.dtsi + * + * 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +/* pcc-table for Poplar JDI */ +&mdss_mdp { + dsi_6: somc,6_panel { + somc,mdss-dsi-pcc-enable; + somc,mdss-dsi-uv-command = [ + 06 01 00 00 00 00 01 DA + 06 01 00 00 00 00 01 DB]; + somc,mdss-dsi-uv-param-type = <4>; + somc,mdss-dsi-pcc-table-size = <226>; + somc,mdss-dsi-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x4380 0x6280 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x4680 0x6280 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x4900 0x6200 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x4B80 0x6200 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x4F00 0x6200 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x5300 0x6180 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x5700 0x6180 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x5A80 0x6100 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x5F00 0x6100 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x6380 0x6080 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x6780 0x6080 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x6B80 0x6080 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x7100 0x6000 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x7680 0x6000 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x7D00 0x6000 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x4900 0x6A00 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x4B80 0x6980 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x4E80 0x6900 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x5180 0x6900 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x5580 0x6880 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x5900 0x6880 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x5C80 0x6800 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x6100 0x6800 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x6500 0x6380 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x6880 0x6380 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x6D00 0x6300 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x7280 0x6300 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x7780 0x6280 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x7D80 0x6280 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x8000 0x6100 0x7E00 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x4E00 0x7100 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x5080 0x7100 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x5480 0x7080 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x5800 0x6B80 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x5A80 0x6B80 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x5F00 0x6B00 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x6300 0x6B00 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x6680 0x6A80 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x6A00 0x6A00 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x6E00 0x6A00 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x7400 0x6980 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7880 0x6980 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x7E80 0x6900 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x8000 0x6380 0x7D80 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x8000 0x6080 0x7780 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x5380 0x7900 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x5680 0x7880 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x5980 0x7380 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x5C80 0x7380 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x6100 0x7300 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x6480 0x7280 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x6780 0x7200 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x6B00 0x7180 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x6F80 0x7100 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x7480 0x7080 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7980 0x7080 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x7F00 0x6B80 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x8000 0x6A00 0x7D80 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x8000 0x6300 0x7780 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x8000 0x6080 0x7180 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x5800 0x8000 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x5B00 0x8000 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x5F00 0x7B00 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x6280 0x7A80 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x6580 0x7A80 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x6900 0x7A00 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x6C80 0x7900 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x7100 0x7880 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x7580 0x7880 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7A80 0x7380 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x7F80 0x7300 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x8000 0x7080 0x7D00 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x8000 0x6980 0x7680 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x8000 0x6300 0x7180 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x6000 0x6C80 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x5680 0x8000 0x7900 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x5A80 0x8000 0x7B00 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x5F00 0x8000 0x7C80 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x6380 0x8000 0x7D80 + 0x00 0x50 0x26 0x28 0x23 0x25 0x6780 0x8000 0x7E80 + 0x00 0x51 0x23 0x25 0x23 0x25 0x6C00 0x8000 0x7F00 + 0x00 0x52 0x20 0x22 0x23 0x25 0x7100 0x8000 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x7680 0x8000 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7B00 0x7B00 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x8000 0x7A80 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x8000 0x7380 0x7C80 + 0x00 0x57 0x11 0x13 0x23 0x25 0x8000 0x7080 0x7680 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x8000 0x6980 0x7200 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x6280 0x6D00 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x5B80 0x6880 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x5500 0x8000 0x7380 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x5980 0x8000 0x7480 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x5E00 0x8000 0x7600 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x6300 0x8000 0x7700 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x6700 0x8000 0x7880 + 0x00 0x60 0x23 0x25 0x20 0x22 0x6B00 0x8000 0x7A00 + 0x00 0x61 0x20 0x22 0x20 0x22 0x7080 0x8000 0x7A80 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7680 0x8000 0x7C00 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7C80 0x8000 0x7D00 + 0x00 0x64 0x17 0x19 0x20 0x22 0x8000 0x7B00 0x7C80 + 0x00 0x65 0x14 0x16 0x20 0x22 0x8000 0x7800 0x7680 + 0x00 0x66 0x11 0x13 0x20 0x22 0x8000 0x7080 0x7200 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x6980 0x6D80 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x6280 0x6900 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x5B80 0x6400 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x5400 0x8000 0x6E80 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x5800 0x8000 0x6F80 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x5C80 0x8000 0x7080 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x6200 0x8000 0x7200 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x6680 0x8000 0x7300 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x6B00 0x8000 0x7400 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x6F80 0x8000 0x7500 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7600 0x8000 0x7680 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x7C00 0x8000 0x7700 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x8000 0x7B00 0x7680 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x8000 0x7800 0x7280 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x8000 0x7080 0x6E00 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x6900 0x6980 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x6200 0x6500 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x5B00 0x5F80 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x5200 0x8000 0x6A00 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x5780 0x8000 0x6B00 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x5B80 0x8000 0x6C00 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x6100 0x8000 0x6D00 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x6580 0x8000 0x6E80 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x6A00 0x8000 0x6F80 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x6F00 0x8000 0x7080 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7580 0x8000 0x7180 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7C00 0x8000 0x7280 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x8000 0x7B00 0x7280 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x7800 0x6E80 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7080 0x6A80 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x6900 0x6600 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x6200 0x6080 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x5A80 0x5C00 + 0x00 0x88 0x32 0x34 0x17 0x19 0x5080 0x8000 0x6580 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x5600 0x8000 0x6700 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x5A80 0x8000 0x6880 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x6000 0x8000 0x6980 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x6480 0x8000 0x6A80 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x6980 0x8000 0x6B80 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x6E80 0x8000 0x6C80 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7500 0x8000 0x6D80 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7B00 0x8000 0x6E80 + 0x00 0x91 0x17 0x19 0x17 0x19 0x8000 0x7B80 0x6F00 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x7800 0x6B00 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7000 0x6700 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x6900 0x6180 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x6180 0x5D00 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x5A00 0x5800 + 0x00 0x97 0x32 0x34 0x14 0x16 0x4F00 0x8000 0x6100 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x5480 0x8000 0x6300 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x5980 0x8000 0x6400 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x5E80 0x8000 0x6580 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x6400 0x8000 0x6700 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x6880 0x8000 0x6800 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x6D80 0x8000 0x6900 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7480 0x8000 0x6A00 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7A80 0x8000 0x6B00 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x8000 0x7B80 0x6B80 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x7380 0x6800 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7000 0x6380 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x6880 0x5E80 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x6180 0x5A00 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x5980 0x5400 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x4E00 0x8000 0x5D00 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x5300 0x8000 0x5E80 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x5800 0x8000 0x6000 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x5D00 0x8000 0x6180 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x6300 0x8000 0x6300 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x6800 0x8000 0x6480 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x6D00 0x8000 0x6580 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7400 0x8000 0x6700 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7A00 0x8000 0x6800 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x8000 0x8000 0x6880 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x7800 0x6480 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7000 0x5F80 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x6880 0x5B80 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x6100 0x5680 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x5900 0x5100 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x4C00 0x8000 0x5980 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x5100 0x8000 0x5B00 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x5780 0x8000 0x5C80 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x5C00 0x8000 0x5D80 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x6200 0x8000 0x5F00 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x6780 0x8000 0x6000 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x6C80 0x8000 0x6200 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7400 0x8000 0x6380 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7A00 0x8000 0x6480 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x8000 0x8000 0x6580 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x7800 0x6100 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7000 0x5D00 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x6880 0x5880 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x6100 0x5300 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x5900 0x4F00 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x4B00 0x8000 0x5580 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x4F80 0x8000 0x5780 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x5600 0x8000 0x5900 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x5B00 0x8000 0x5A80 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x6100 0x8000 0x5C00 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x6680 0x8000 0x5D00 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x6B80 0x8000 0x5E80 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7280 0x8000 0x6000 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7980 0x8000 0x6080 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x8000 0x8000 0x6280 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x8000 0x7800 0x5E80 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7000 0x5A80 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x6880 0x5580 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x6080 0x5080 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x5880 0x4C80 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x4980 0x8000 0x5280 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x4E80 0x8000 0x5380 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x5480 0x8000 0x5580 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x5A00 0x8000 0x5700 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x6000 0x8000 0x5880 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x6580 0x8000 0x5A80 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x6B00 0x8000 0x5B80 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7180 0x8000 0x5C80 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7880 0x8000 0x5E00 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x8000 0x8000 0x5F80 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x8000 0x7800 0x5C00 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7000 0x5780 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x6880 0x5300 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x6080 0x4E80 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x5800 0x4980 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-srgb-pcc-enable; + somc,mdss-dsi-srgb-pcc-table-size = <226>; + somc,mdss-dsi-srgb-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x4580 0x6800 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x4880 0x6800 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x4B00 0x6380 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x4E00 0x6380 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x5180 0x6300 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x5500 0x6300 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x5880 0x6280 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x5D00 0x6280 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x6180 0x6200 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x6580 0x6200 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x6980 0x6180 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x6E00 0x6180 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x7300 0x6180 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x7800 0x6100 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x7E80 0x6100 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x4B00 0x6B80 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x4D80 0x6B00 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x5080 0x6A80 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x5400 0x6A00 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x5700 0x6A00 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x5B00 0x6A00 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x5F80 0x6980 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x6380 0x6900 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x6780 0x6900 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x6B80 0x6880 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x6F80 0x6880 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x7400 0x6800 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x7980 0x6800 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x7F80 0x6800 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x8000 0x6180 0x7B00 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x5000 0x7280 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x5380 0x7200 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x5600 0x7180 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x5980 0x7180 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x5D00 0x7080 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x6180 0x7080 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x6580 0x7000 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x6900 0x7000 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x6C80 0x6B80 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x7100 0x6B00 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x7580 0x6B00 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7A80 0x6A80 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x8000 0x6A80 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x8000 0x6800 0x7B00 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x8000 0x6100 0x7480 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x5580 0x7A00 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x5800 0x7980 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x5B80 0x7900 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x5F80 0x7880 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x6380 0x7800 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x6680 0x7380 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x6A00 0x7300 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x6D80 0x7300 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x7200 0x7280 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x7680 0x7200 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7C00 0x7180 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x8000 0x7100 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x8000 0x6A80 0x7A80 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x8000 0x6500 0x7480 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x8000 0x6080 0x6E80 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x5700 0x8000 0x7D80 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x5B80 0x8000 0x7E80 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x6080 0x8000 0x7F80 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x6500 0x8000 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x6800 0x7B00 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x6B80 0x7A80 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x6F00 0x7A00 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x7300 0x7A00 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x7780 0x7900 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7C80 0x7880 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x8000 0x7380 0x7F80 + 0x00 0x48 0x11 0x13 0x26 0x28 0x8000 0x7100 0x7980 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x8000 0x6A00 0x7480 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x8000 0x6380 0x6E80 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x6000 0x6A00 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x5600 0x8000 0x7680 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x5A80 0x8000 0x7780 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x5F80 0x8000 0x7900 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x6480 0x8000 0x7A80 + 0x00 0x50 0x26 0x28 0x23 0x25 0x6880 0x8000 0x7B80 + 0x00 0x51 0x23 0x25 0x23 0x25 0x6C80 0x8000 0x7D00 + 0x00 0x52 0x20 0x22 0x23 0x25 0x7180 0x8000 0x7E00 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x7680 0x8000 0x7F00 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7D00 0x8000 0x7F80 + 0x00 0x55 0x17 0x19 0x23 0x25 0x8000 0x7B00 0x7F00 + 0x00 0x56 0x14 0x16 0x23 0x25 0x8000 0x7800 0x7980 + 0x00 0x57 0x11 0x13 0x23 0x25 0x8000 0x7080 0x7480 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x8000 0x6A00 0x6F00 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x6300 0x6A80 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x6000 0x6580 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x5500 0x8000 0x7080 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x5980 0x8000 0x7180 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x5E80 0x8000 0x7380 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x6380 0x8000 0x7480 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x6800 0x8000 0x7580 + 0x00 0x60 0x23 0x25 0x20 0x22 0x6C80 0x8000 0x7680 + 0x00 0x61 0x20 0x22 0x20 0x22 0x7100 0x8000 0x7800 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7600 0x8000 0x7880 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7C80 0x8000 0x7980 + 0x00 0x64 0x17 0x19 0x20 0x22 0x8000 0x7B00 0x7900 + 0x00 0x65 0x14 0x16 0x20 0x22 0x8000 0x7380 0x7480 + 0x00 0x66 0x11 0x13 0x20 0x22 0x8000 0x7100 0x6F80 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x6980 0x6B00 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x6300 0x6680 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x5B80 0x6100 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x5400 0x8000 0x6B80 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x5800 0x8000 0x6D00 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x5D00 0x8000 0x6E00 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x6280 0x8000 0x6F00 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x6700 0x8000 0x7000 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x6B80 0x8000 0x7180 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x7080 0x8000 0x7300 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7580 0x8000 0x7400 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x7C00 0x8000 0x7500 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x8000 0x7B00 0x7480 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x8000 0x7380 0x6F80 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x8000 0x7080 0x6B80 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x6980 0x6780 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x6280 0x6280 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x5B00 0x5C00 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x5300 0x8000 0x6780 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x5700 0x8000 0x6880 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x5C00 0x8000 0x6A00 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x6180 0x8000 0x6A80 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x6600 0x8000 0x6C00 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x6B00 0x8000 0x6D00 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x6F80 0x8000 0x6E00 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7500 0x8000 0x6F00 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7B00 0x8000 0x7000 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x8000 0x7B00 0x7000 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x7380 0x6C00 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7080 0x6800 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x6980 0x6380 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x6280 0x5E00 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x5A80 0x5800 + 0x00 0x88 0x32 0x34 0x17 0x19 0x5100 0x8000 0x6300 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x5600 0x8000 0x6480 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x5A80 0x8000 0x6580 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x6080 0x8000 0x6700 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x6580 0x8000 0x6880 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x6A00 0x8000 0x6900 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x6F00 0x8000 0x6A80 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7480 0x8000 0x6B00 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7B00 0x8000 0x6C00 + 0x00 0x91 0x17 0x19 0x17 0x19 0x8000 0x7B80 0x6C80 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x7380 0x6880 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7080 0x6480 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x6980 0x5F80 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x6200 0x5A00 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x5A00 0x5500 + 0x00 0x97 0x32 0x34 0x14 0x16 0x4F80 0x8000 0x5E80 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x5480 0x8000 0x6000 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x5980 0x8000 0x6180 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x5F80 0x8000 0x6300 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x6500 0x8000 0x6480 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x6980 0x8000 0x6580 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x6E80 0x8000 0x6680 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7400 0x8000 0x6800 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7A80 0x8000 0x6880 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x8000 0x7B80 0x6900 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x7800 0x6580 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7080 0x6100 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x6980 0x5B80 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x6180 0x5680 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x5980 0x5180 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x4E00 0x8000 0x5A00 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x5380 0x8000 0x5B80 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x5800 0x8000 0x5D00 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x5D80 0x8000 0x5F00 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x6400 0x8000 0x6080 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x6900 0x8000 0x6180 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x6E00 0x8000 0x6300 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7400 0x8000 0x6480 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7A00 0x8000 0x6580 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x8000 0x8000 0x6600 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x7800 0x6200 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7080 0x5D80 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x6900 0x5800 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x6180 0x5400 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x5980 0x4E80 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x4C80 0x8000 0x5600 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x5180 0x8000 0x5780 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x5700 0x8000 0x5900 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x5C80 0x8000 0x5B00 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x6300 0x8000 0x5C80 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x6800 0x8000 0x5E00 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x6D00 0x8000 0x5F80 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7300 0x8000 0x6080 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7980 0x8000 0x6200 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x8000 0x8000 0x6380 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x7800 0x5F00 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7080 0x5A00 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x6900 0x5580 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x6100 0x5080 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x5900 0x4C00 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x4B00 0x8000 0x5300 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x5000 0x8000 0x5500 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x5600 0x8000 0x5600 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x5B80 0x8000 0x5780 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x6200 0x8000 0x5880 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x6780 0x8000 0x5A00 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x6C80 0x8000 0x5B80 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7280 0x8000 0x5D00 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7880 0x8000 0x5E80 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x8000 0x8000 0x6000 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x8000 0x7800 0x5B80 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7000 0x5780 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x6900 0x5300 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x6100 0x4E00 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x5880 0x4A00 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x4980 0x8000 0x4F80 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x4E80 0x8000 0x5100 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x5480 0x8000 0x5300 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x5A00 0x8000 0x5480 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x6080 0x8000 0x5600 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x6680 0x8000 0x5700 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x6C00 0x8000 0x5880 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7200 0x8000 0x5A00 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7800 0x8000 0x5B80 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x7F80 0x8000 0x5C80 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x8000 0x7800 0x5880 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7000 0x5500 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x6880 0x5000 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x6080 0x4C00 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x5380 0x4780 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-vivid-pcc-enable; + somc,mdss-dsi-vivid-pcc-table-size = <226>; + somc,mdss-dsi-vivid-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x6180 0x7280 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x6300 0x7200 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x6500 0x7200 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x6700 0x7200 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x6880 0x7180 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x6A80 0x7180 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x6C80 0x7180 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x6F80 0x7180 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x7180 0x7100 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x7400 0x7100 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x7600 0x7100 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x7800 0x7100 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x7A80 0x7100 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x7C80 0x7100 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x7F80 0x7080 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x6500 0x7800 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x6680 0x7380 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x6800 0x7380 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x6A00 0x7380 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x6C00 0x7300 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x6E80 0x7300 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x7080 0x7300 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x7280 0x7300 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x7480 0x7300 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x7680 0x7280 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x7880 0x7280 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x7B00 0x7280 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x7D00 0x7280 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x8000 0x7200 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x8000 0x7100 0x7E00 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x6800 0x7980 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x6980 0x7980 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x6B80 0x7900 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x6D00 0x7900 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x6F80 0x7880 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x7180 0x7880 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x7380 0x7880 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x7500 0x7800 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x7700 0x7800 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x7900 0x7800 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x7B80 0x7380 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7D80 0x7380 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x8000 0x7380 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x8000 0x7280 0x7E00 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x8000 0x7080 0x7B00 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x6B00 0x7B00 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x6C80 0x7B00 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x6F00 0x7A80 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x7080 0x7A80 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x7280 0x7A00 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x7400 0x7A00 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x7600 0x7A00 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x7780 0x7980 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x7A00 0x7980 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x7C00 0x7900 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7E00 0x7900 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x8000 0x7900 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x8000 0x7380 0x7D80 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x8000 0x7200 0x7B00 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x8000 0x7080 0x7880 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x6C00 0x8000 0x7F00 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x6F00 0x8000 0x7F80 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x7100 0x8000 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x7380 0x8000 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x7500 0x7B80 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x7700 0x7B80 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x7880 0x7B00 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x7A80 0x7B00 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x7C80 0x7B00 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7E80 0x7A80 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x8000 0x7A00 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x8000 0x7880 0x7D80 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x8000 0x7380 0x7B00 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x8000 0x7200 0x7880 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x7080 0x7600 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x6B80 0x8000 0x7C00 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x6E80 0x8000 0x7C80 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x7080 0x8000 0x7D80 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x7300 0x8000 0x7E00 + 0x00 0x50 0x26 0x28 0x23 0x25 0x7500 0x8000 0x7E00 + 0x00 0x51 0x23 0x25 0x23 0x25 0x7700 0x8000 0x7E80 + 0x00 0x52 0x20 0x22 0x23 0x25 0x7980 0x8000 0x7F00 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x7C80 0x8000 0x7F80 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7E80 0x8000 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x8000 0x7B80 0x7F80 + 0x00 0x56 0x14 0x16 0x23 0x25 0x8000 0x7A00 0x7D80 + 0x00 0x57 0x11 0x13 0x23 0x25 0x8000 0x7880 0x7B00 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x8000 0x7300 0x7900 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x7200 0x7600 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x7000 0x7400 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x6A80 0x8000 0x7980 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x6D80 0x8000 0x7A00 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x7000 0x8000 0x7A80 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x7280 0x8000 0x7B00 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x7480 0x8000 0x7B80 + 0x00 0x60 0x23 0x25 0x20 0x22 0x7700 0x8000 0x7C00 + 0x00 0x61 0x20 0x22 0x20 0x22 0x7980 0x8000 0x7C80 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7C00 0x8000 0x7D00 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7E80 0x8000 0x7D80 + 0x00 0x64 0x17 0x19 0x20 0x22 0x8000 0x7B80 0x7D80 + 0x00 0x65 0x14 0x16 0x20 0x22 0x8000 0x7A00 0x7B00 + 0x00 0x66 0x11 0x13 0x20 0x22 0x8000 0x7880 0x7900 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x7300 0x7680 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x7180 0x7480 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x7000 0x7180 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x6A00 0x8000 0x7700 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x6C80 0x8000 0x7780 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x6F80 0x8000 0x7800 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x7200 0x8000 0x7900 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x7400 0x8000 0x7980 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x7700 0x8000 0x7A00 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x7900 0x8000 0x7A80 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7C00 0x8000 0x7B00 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x7E00 0x8000 0x7B80 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x8000 0x7B80 0x7B00 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x8000 0x7A00 0x7900 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x8000 0x7880 0x7700 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7300 0x7500 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x7180 0x7280 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x7000 0x6F80 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x6980 0x8000 0x7500 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x6C00 0x8000 0x7600 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x6F00 0x8000 0x7600 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x7180 0x8000 0x7680 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x7400 0x8000 0x7700 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x7680 0x8000 0x7780 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x7900 0x8000 0x7800 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7B80 0x8000 0x7880 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7E00 0x8000 0x7900 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x8000 0x7B80 0x7900 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x7A00 0x7700 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7880 0x7580 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7300 0x7300 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x7180 0x7080 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x6B80 0x6D80 + 0x00 0x88 0x32 0x34 0x17 0x19 0x6880 0x8000 0x7300 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x6B00 0x8000 0x7380 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x6E80 0x8000 0x7400 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x7100 0x8000 0x7500 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x7400 0x8000 0x7580 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x7600 0x8000 0x7600 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x7880 0x8000 0x7600 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7B80 0x8000 0x7680 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7D80 0x8000 0x7700 + 0x00 0x91 0x17 0x19 0x17 0x19 0x8000 0x8000 0x7780 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x7A00 0x7580 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7880 0x7380 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7300 0x7100 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x7100 0x6E80 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x6B00 0x6B80 + 0x00 0x97 0x32 0x34 0x14 0x16 0x6800 0x8000 0x7080 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x6A80 0x8000 0x7180 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x6D00 0x8000 0x7200 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x7080 0x8000 0x7280 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x7380 0x8000 0x7380 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x7580 0x8000 0x7400 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x7800 0x8000 0x7480 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7B00 0x8000 0x7500 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7D80 0x8000 0x7600 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x8000 0x8000 0x7600 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x7A00 0x7400 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7880 0x7180 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x7300 0x6F00 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x7100 0x6C80 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x6B80 0x6980 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x6700 0x8000 0x6E80 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x6A00 0x8000 0x6F00 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x6C80 0x8000 0x7000 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x7000 0x8000 0x7080 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x7300 0x8000 0x7180 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x7580 0x8000 0x7200 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x7800 0x8000 0x7280 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7B00 0x8000 0x7380 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7D80 0x8000 0x7400 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x8000 0x8000 0x7480 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x7A00 0x7200 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7880 0x7000 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x7300 0x6D80 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x7100 0x6B00 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x6B00 0x6800 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x6600 0x8000 0x6C80 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x6900 0x8000 0x6D00 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x6C00 0x8000 0x6E00 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x6F80 0x8000 0x6F00 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x7280 0x8000 0x6F80 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x7500 0x8000 0x7000 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x7780 0x8000 0x7100 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7A80 0x8000 0x7180 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7D00 0x8000 0x7200 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x8000 0x8000 0x7300 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x7A80 0x7080 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7880 0x6E80 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x7300 0x6C00 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x7100 0x6900 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x6B00 0x6680 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x6580 0x8000 0x6A80 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x6880 0x8000 0x6B80 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x6B00 0x8000 0x6C00 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x6F00 0x8000 0x6D00 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x7200 0x8000 0x6E00 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x7480 0x8000 0x6E80 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x7700 0x8000 0x6F00 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7A00 0x8000 0x7000 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7D00 0x8000 0x7080 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x8000 0x8000 0x7100 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x8000 0x7A80 0x6F00 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7880 0x6D00 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x7280 0x6A80 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x7080 0x6780 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x6A80 0x6500 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x6480 0x8000 0x6880 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x6780 0x8000 0x6980 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x6A80 0x8000 0x6A80 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x6E00 0x8000 0x6B80 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x7180 0x8000 0x6C00 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x7400 0x8000 0x6D00 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x7700 0x8000 0x6D80 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7A00 0x8000 0x6E80 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7C80 0x8000 0x6F00 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x8000 0x8000 0x6F80 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x8000 0x7A80 0x6D80 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7880 0x6B80 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x7280 0x6900 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x7080 0x6600 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x6A00 0x6380 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-hdr-pcc-enable; + somc,mdss-dsi-hdr-pcc-table-size = <226>; + somc,mdss-dsi-hdr-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x6100 0x7180 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x6280 0x7200 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x6480 0x7180 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x6600 0x7180 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x6800 0x7180 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x6A00 0x7100 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x6C80 0x7100 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x6E80 0x7100 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x7100 0x7100 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x7380 0x7080 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x7580 0x7080 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x7780 0x7080 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x7A00 0x7080 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x7D00 0x7080 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x8000 0x7080 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x6400 0x7380 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x6600 0x7380 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x6780 0x7300 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x6980 0x7300 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x6B80 0x7280 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x6D80 0x7280 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x6F80 0x7280 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x7200 0x7280 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x7400 0x7200 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x7600 0x7200 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x7800 0x7200 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x7A80 0x7200 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x7D80 0x7200 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x8000 0x7180 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x8000 0x7000 0x7C80 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x6780 0x7900 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x6900 0x7900 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x6B00 0x7880 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x6D00 0x7880 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x6F00 0x7880 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x7100 0x7800 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x7300 0x7800 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x7480 0x7800 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x7700 0x7380 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x7900 0x7380 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x7B00 0x7380 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7E00 0x7300 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x8000 0x7280 0x7F80 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x8000 0x7180 0x7C80 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x8000 0x7000 0x7980 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x6A80 0x7B00 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x6C00 0x7A80 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x6E00 0x7A80 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x7000 0x7A00 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x7200 0x7A00 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x7380 0x7980 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x7580 0x7980 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x7700 0x7980 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x7980 0x7900 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x7C00 0x7900 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7E00 0x7880 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x8000 0x7800 0x7F80 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x8000 0x7280 0x7C80 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x8000 0x7180 0x7980 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x8000 0x6B80 0x7700 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x6C00 0x8000 0x7F00 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x6E00 0x8000 0x7F80 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x7080 0x8000 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x7280 0x8000 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x7400 0x7B80 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x7600 0x7B00 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x7800 0x7B00 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x7A00 0x7A80 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x7C80 0x7A80 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7E80 0x7A80 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x8000 0x7980 0x7F00 + 0x00 0x48 0x11 0x13 0x26 0x28 0x8000 0x7800 0x7C00 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x8000 0x7280 0x7A00 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x8000 0x7100 0x7700 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x6B80 0x7480 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x6B00 0x8000 0x7B80 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x6D80 0x8000 0x7C00 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x7000 0x8000 0x7D00 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x7280 0x8000 0x7D80 + 0x00 0x50 0x26 0x28 0x23 0x25 0x7480 0x8000 0x7E80 + 0x00 0x51 0x23 0x25 0x23 0x25 0x7700 0x8000 0x7F00 + 0x00 0x52 0x20 0x22 0x23 0x25 0x7980 0x8000 0x7F00 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x7C00 0x8000 0x7F80 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7F00 0x8000 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x8000 0x7B00 0x7F00 + 0x00 0x56 0x14 0x16 0x23 0x25 0x8000 0x7980 0x7C00 + 0x00 0x57 0x11 0x13 0x23 0x25 0x8000 0x7800 0x7A00 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x8000 0x7280 0x7780 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x7100 0x7480 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x6B00 0x7280 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x6A80 0x8000 0x7880 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x6D00 0x8000 0x7980 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x6F80 0x8000 0x7A00 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x7200 0x8000 0x7A80 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x7400 0x8000 0x7B00 + 0x00 0x60 0x23 0x25 0x20 0x22 0x7700 0x8000 0x7B80 + 0x00 0x61 0x20 0x22 0x20 0x22 0x7900 0x8000 0x7C00 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7C00 0x8000 0x7C80 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7E80 0x8000 0x7D00 + 0x00 0x64 0x17 0x19 0x20 0x22 0x8000 0x7B00 0x7C00 + 0x00 0x65 0x14 0x16 0x20 0x22 0x8000 0x7980 0x7A00 + 0x00 0x66 0x11 0x13 0x20 0x22 0x8000 0x7800 0x7780 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x7200 0x7500 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x7100 0x7300 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x6B00 0x7000 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x6980 0x8000 0x7680 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x6C00 0x8000 0x7700 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x6F00 0x8000 0x7780 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x7180 0x8000 0x7800 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x7380 0x8000 0x7900 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x7680 0x8000 0x7980 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x7900 0x8000 0x7A00 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7B80 0x8000 0x7A80 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x7E80 0x8000 0x7B00 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x8000 0x7B00 0x7A00 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x8000 0x7980 0x7780 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x8000 0x7800 0x7580 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7200 0x7300 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x7080 0x7080 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x6A80 0x6D80 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x6900 0x8000 0x7400 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x6B80 0x8000 0x7480 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x6E80 0x8000 0x7500 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x7100 0x8000 0x7600 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x7380 0x8000 0x7680 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x7600 0x8000 0x7700 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x7880 0x8000 0x7780 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7B80 0x8000 0x7800 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7E80 0x8000 0x7800 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x8000 0x7B00 0x7800 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x7980 0x7580 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7800 0x7300 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7200 0x7100 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x7080 0x6E80 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x6A80 0x6B80 + 0x00 0x88 0x32 0x34 0x17 0x19 0x6800 0x8000 0x7200 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x6B00 0x8000 0x7200 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x6D80 0x8000 0x7300 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x7080 0x8000 0x7380 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x7380 0x8000 0x7400 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x7580 0x8000 0x7500 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x7800 0x8000 0x7580 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7B00 0x8000 0x7600 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7E00 0x8000 0x7680 + 0x00 0x91 0x17 0x19 0x17 0x19 0x8000 0x7B00 0x7600 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x7980 0x7380 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7380 0x7180 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7200 0x6F00 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x7080 0x6C80 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x6A00 0x6980 + 0x00 0x97 0x32 0x34 0x14 0x16 0x6780 0x8000 0x6F80 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x6A00 0x8000 0x7080 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x6D00 0x8000 0x7100 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x7000 0x8000 0x7200 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x7300 0x8000 0x7280 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x7580 0x8000 0x7300 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x7800 0x8000 0x7380 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7B00 0x8000 0x7400 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7E00 0x8000 0x7480 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x8000 0x7B00 0x7400 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x7980 0x7280 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7380 0x7000 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x7200 0x6D80 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x7000 0x6A80 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x6A00 0x6780 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x6680 0x8000 0x6D80 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x6980 0x8000 0x6E80 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x6C80 0x8000 0x6F00 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x6F80 0x8000 0x7000 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x7280 0x8000 0x7080 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x7500 0x8000 0x7180 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x7780 0x8000 0x7200 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7A80 0x8000 0x7280 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7E00 0x8000 0x7280 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x8000 0x7B00 0x7280 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x7980 0x7080 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7380 0x6E00 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x7200 0x6B80 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x7000 0x6900 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x6A00 0x6600 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x6580 0x8000 0x6B80 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x6880 0x8000 0x6C80 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x6B80 0x8000 0x6D00 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x6F00 0x8000 0x6E00 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x7200 0x8000 0x6E80 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x7480 0x8000 0x6F80 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x7700 0x8000 0x7000 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7A80 0x8000 0x7100 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7D80 0x8000 0x7180 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x8000 0x7B00 0x7100 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x7980 0x6F00 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7380 0x6C80 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x7200 0x6A00 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x7000 0x6700 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x6980 0x6400 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x6500 0x8000 0x6980 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x6800 0x8000 0x6A80 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x6B00 0x8000 0x6B00 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x6E00 0x8000 0x6B80 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x7180 0x8000 0x6C80 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x7400 0x8000 0x6D80 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x7700 0x8000 0x6E80 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7A00 0x8000 0x6F00 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7D80 0x8000 0x6F80 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x8000 0x7B80 0x6F80 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x8000 0x7980 0x6D80 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7380 0x6B00 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x7200 0x6880 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x6B80 0x6580 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x6980 0x6280 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x6400 0x8000 0x6780 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x6700 0x8000 0x6880 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x6A80 0x8000 0x6980 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x6D80 0x8000 0x6A80 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x7100 0x8000 0x6B00 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x7380 0x8000 0x6C00 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x7700 0x8000 0x6C00 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7980 0x8000 0x6D80 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7D00 0x8000 0x6E00 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x8000 0x7B80 0x6E00 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x8000 0x7980 0x6C00 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7380 0x6980 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x7180 0x6700 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x6B80 0x6400 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x6900 0x6180 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-poplar-id9_pcc.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-poplar-id9_pcc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c97fa7d3d2ae4eff680d948f2b6cd6aee7327e4c --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-poplar-id9_pcc.dtsi @@ -0,0 +1,947 @@ +/* arch/arm64/boot/dts/qcom/dsi-panel-poplar-id9_pcc.dtsi + * + * 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +/* pcc-table for Poplar Sharp */ +&mdss_mdp { + dsi_9: somc,9_panel { + somc,mdss-dsi-pcc-enable; + somc,mdss-dsi-uv-command = [ + 06 01 00 00 00 00 01 DA + 06 01 00 00 00 00 01 DB]; + somc,mdss-dsi-uv-param-type = <4>; + somc,mdss-dsi-pcc-table-size = <226>; + somc,mdss-dsi-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x3A80 0x5A80 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x3D80 0x5A00 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x4080 0x5A00 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x4380 0x5980 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x4700 0x5980 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x4A00 0x5900 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x4D80 0x5900 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x5180 0x5900 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x5580 0x5900 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x5980 0x5900 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x5E00 0x5880 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x6380 0x5880 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x6900 0x5880 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x6E80 0x5880 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x7480 0x5880 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x4000 0x6180 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x4300 0x6100 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x4600 0x6100 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x4900 0x6080 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x4C00 0x6080 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x4F80 0x6000 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x5300 0x6000 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x5780 0x5B80 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x5B00 0x5B80 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x5F80 0x5B00 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x6500 0x5B00 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x6A80 0x5B00 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x6F80 0x5B00 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x7500 0x5B00 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x7B80 0x5A80 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x4580 0x6880 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x4880 0x6800 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x4B00 0x6800 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x4E00 0x6380 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x5180 0x6300 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x5580 0x6300 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x5900 0x6280 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x5C80 0x6280 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x6180 0x6200 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x6600 0x6200 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x6B80 0x6180 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7080 0x6180 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x7600 0x6180 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x7C00 0x6100 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x8000 0x5B80 0x7E00 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x4A00 0x6B80 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x4D00 0x6B00 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x5000 0x6A80 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x5300 0x6A80 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x5780 0x6A00 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x5A80 0x6980 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x5E80 0x6900 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x6300 0x6900 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x6780 0x6900 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x6C80 0x6880 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7180 0x6800 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x7680 0x6800 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x7D00 0x6380 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x8000 0x6200 0x7D80 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x8000 0x5B00 0x7680 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x4F00 0x7280 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x5200 0x7200 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x5500 0x7180 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x5880 0x7100 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x5B80 0x7080 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x5F80 0x7080 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x6400 0x7000 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x6880 0x6B80 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x6D80 0x6B00 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7200 0x6B00 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x7700 0x6A80 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x7D00 0x6A00 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x8000 0x6900 0x7D80 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x8000 0x6200 0x7780 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x5B00 0x7180 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x5380 0x7A00 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x5700 0x7980 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x5A00 0x7900 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x5D00 0x7800 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x6100 0x7800 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x6580 0x7380 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x6980 0x7300 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x6E00 0x7200 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7300 0x7200 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x7780 0x7180 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x7D80 0x7100 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x8000 0x6B80 0x7D80 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x8000 0x6880 0x7780 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x6180 0x7200 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x5A80 0x6C80 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x5500 0x8000 0x7D80 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x5980 0x8000 0x7E80 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x5D80 0x8000 0x7F80 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x6280 0x8000 0x8000 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x6680 0x7B00 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x6B00 0x7A80 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x6F00 0x7A00 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7380 0x7980 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7800 0x7900 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x7E00 0x7800 0x8000 + 0x00 0x65 0x14 0x16 0x20 0x22 0x8000 0x7200 0x7D80 + 0x00 0x66 0x11 0x13 0x20 0x22 0x8000 0x6B00 0x7800 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x6880 0x7280 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x6180 0x6D80 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x5A00 0x6700 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x5400 0x8000 0x7700 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x5880 0x8000 0x7780 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x5C80 0x8000 0x7900 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x6180 0x8000 0x7B00 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x6700 0x8000 0x7C80 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x6C80 0x8000 0x7D80 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x7180 0x8000 0x7E00 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7700 0x8000 0x7F00 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x7E00 0x8000 0x8000 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x8000 0x7980 0x7D80 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x8000 0x7280 0x7780 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x8000 0x6B00 0x7300 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x6800 0x6E00 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x6100 0x6880 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x5980 0x6280 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x5280 0x8000 0x7200 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x5780 0x8000 0x7300 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x5B80 0x8000 0x7480 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x6080 0x8000 0x7580 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x6600 0x8000 0x7680 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x6C00 0x8000 0x7780 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x7100 0x8000 0x7800 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7700 0x8000 0x7980 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7D80 0x8000 0x7B00 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x8000 0x7980 0x7780 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x7200 0x7380 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x6B00 0x6F00 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x6800 0x6980 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x6080 0x6400 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x5900 0x5E80 + 0x00 0x88 0x32 0x34 0x17 0x19 0x5180 0x8000 0x6D00 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x5680 0x8000 0x6E80 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x5B00 0x8000 0x6F80 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x5F80 0x8000 0x7100 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x6580 0x8000 0x7200 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x6B80 0x8000 0x7300 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x7080 0x8000 0x7400 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7680 0x8000 0x7500 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7D80 0x8000 0x7600 + 0x00 0x91 0x17 0x19 0x17 0x19 0x8000 0x7A00 0x7400 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x7200 0x6F80 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x6B00 0x6B00 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x6380 0x6500 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x6080 0x6000 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x5900 0x5B80 + 0x00 0x97 0x32 0x34 0x14 0x16 0x5000 0x8000 0x6800 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x5500 0x8000 0x6980 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x5980 0x8000 0x6B00 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x5E80 0x8000 0x6C80 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x6480 0x8000 0x6D80 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x6A80 0x8000 0x6F00 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x7000 0x8000 0x7000 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7600 0x8000 0x7100 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7D00 0x8000 0x7200 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x8000 0x7A00 0x7080 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x7280 0x6C00 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x6A80 0x6680 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x6380 0x6180 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x6000 0x5D00 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x5880 0x5800 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x4F00 0x8000 0x6380 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x5380 0x8000 0x6500 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x5900 0x8000 0x6680 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x5D80 0x8000 0x6780 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x6380 0x8000 0x6900 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x6980 0x8000 0x6B00 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x6F80 0x8000 0x6C00 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7580 0x8000 0x6D00 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7C00 0x8000 0x6E00 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x8000 0x7A00 0x6C80 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x7200 0x6780 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x6A80 0x6300 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x6380 0x5E80 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x5B80 0x5A00 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x5800 0x5480 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x4D80 0x8000 0x6000 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x5280 0x8000 0x6100 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x5800 0x8000 0x6280 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x5C80 0x8000 0x6380 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x6280 0x8000 0x6500 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x6880 0x8000 0x6680 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x6F00 0x8000 0x6780 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7500 0x8000 0x6900 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7C00 0x8000 0x6A80 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x8000 0x7A00 0x6880 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x7200 0x6400 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x6A80 0x6000 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x6300 0x5B80 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x5B80 0x5680 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x5380 0x5200 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x4C80 0x8000 0x5D00 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x5180 0x8000 0x5E00 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x5700 0x8000 0x5F00 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x5B80 0x8000 0x6000 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x6180 0x8000 0x6180 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x6800 0x8000 0x6280 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x6E00 0x8000 0x6400 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7480 0x8000 0x6580 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7B80 0x8000 0x6680 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x8000 0x7A00 0x6580 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x8000 0x7200 0x6100 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x6A80 0x5D00 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x6300 0x5900 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x5B00 0x5400 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x5380 0x5000 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x4B80 0x8000 0x5980 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x5000 0x8000 0x5A80 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x5580 0x8000 0x5C00 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x5B00 0x8000 0x5D80 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x6080 0x8000 0x5E80 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x6700 0x8000 0x5F80 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x6D80 0x8000 0x6080 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7400 0x8000 0x6200 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7B00 0x8000 0x6300 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x8000 0x7A80 0x6280 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x8000 0x7200 0x5E80 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x6A80 0x5A80 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x6280 0x5680 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x5B00 0x5200 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x5300 0x4E00 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-srgb-pcc-enable; + somc,mdss-dsi-srgb-pcc-table-size = <226>; + somc,mdss-dsi-srgb-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x3A80 0x5A80 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x3E00 0x5A80 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x4100 0x5A00 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x4480 0x5A00 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x4780 0x5980 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x4A80 0x5980 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x4E00 0x5980 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x5200 0x5900 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x5600 0x5900 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x5A00 0x5900 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x5F00 0x5880 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x6400 0x5880 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x6980 0x5880 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x6F80 0x5880 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x7480 0x5880 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x4100 0x6200 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x4400 0x6180 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x4700 0x6180 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x4A00 0x6100 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x4D00 0x6100 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x5000 0x6080 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x5400 0x6080 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x5780 0x6000 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x5C00 0x6000 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x6000 0x5B80 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x6600 0x5B80 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x6B80 0x5B80 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x7080 0x5B00 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x7500 0x5B00 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x7B80 0x5B00 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x4680 0x6900 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x4900 0x6880 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x4B80 0x6880 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x4F00 0x6880 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x5280 0x6800 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x5580 0x6380 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x5900 0x6380 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x5D80 0x6300 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x6280 0x6300 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x6700 0x6280 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x6C80 0x6280 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7100 0x6200 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x7600 0x6200 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x7C00 0x6180 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x8000 0x6000 0x7D00 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x4B00 0x7000 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x4D80 0x6B80 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x5100 0x6B00 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x5400 0x6B00 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x5700 0x6A80 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x5B00 0x6A00 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x5F00 0x6A00 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x6380 0x6980 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x6880 0x6980 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x6D00 0x6900 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7200 0x6880 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x7680 0x6880 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x7D00 0x6800 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x8000 0x6300 0x7D00 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x8000 0x6000 0x7580 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x4F80 0x7300 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x5300 0x7280 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x5580 0x7200 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x5880 0x7180 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x5C80 0x7180 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x6000 0x7100 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x6500 0x7080 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x6980 0x7000 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x6E00 0x6B80 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7280 0x6B80 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x7700 0x6B00 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x7D00 0x6A80 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x8000 0x6980 0x7D00 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x8000 0x6280 0x7600 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x5B80 0x7100 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x5480 0x7A00 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x5700 0x7980 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x5A00 0x7900 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x5E00 0x7800 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x6200 0x7800 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x6680 0x7380 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x6B00 0x7300 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x6F00 0x7280 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7380 0x7200 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x7780 0x7180 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x7D80 0x7180 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x8000 0x7000 0x7D00 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x8000 0x6900 0x7600 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x6200 0x7180 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x5B00 0x6B80 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x5580 0x8000 0x7C00 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x5980 0x8000 0x7D80 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x5E80 0x8000 0x7F80 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x6380 0x8000 0x8000 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x6780 0x7B00 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x6C00 0x7A80 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x7000 0x7A00 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7380 0x7980 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7800 0x7900 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x7E00 0x7800 0x8000 + 0x00 0x65 0x14 0x16 0x20 0x22 0x8000 0x7280 0x7D00 + 0x00 0x66 0x11 0x13 0x20 0x22 0x8000 0x6B80 0x7680 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x6900 0x7180 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x6200 0x6C80 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x5A80 0x6680 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x5500 0x8000 0x7580 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x5880 0x8000 0x7680 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x5D80 0x8000 0x7800 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x6280 0x8000 0x7980 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x6800 0x8000 0x7B00 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x6D00 0x8000 0x7C00 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x7200 0x8000 0x7D80 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7700 0x8000 0x7F00 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x7E00 0x8000 0x8000 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x8000 0x7980 0x7D00 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x8000 0x7280 0x7680 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x8000 0x6B80 0x7200 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x6880 0x6D80 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x6180 0x6780 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x5A00 0x6180 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x5380 0x8000 0x7100 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x5780 0x8000 0x7200 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x5C80 0x8000 0x7300 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x6100 0x8000 0x7400 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x6700 0x8000 0x7500 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x6D00 0x8000 0x7600 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x7180 0x8000 0x7700 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7700 0x8000 0x7800 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x7D80 0x8000 0x7980 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x8000 0x7980 0x7700 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x7280 0x7280 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x6B80 0x6E00 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x6880 0x6880 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x6100 0x6300 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x5980 0x5E00 + 0x00 0x88 0x32 0x34 0x17 0x19 0x5280 0x8000 0x6C80 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x5680 0x8000 0x6D80 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x5B00 0x8000 0x6F00 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x6000 0x8000 0x7000 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x6600 0x8000 0x7100 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x6C80 0x8000 0x7200 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x7100 0x8000 0x7300 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7680 0x8000 0x7400 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x7D00 0x8000 0x7480 + 0x00 0x91 0x17 0x19 0x17 0x19 0x8000 0x7A00 0x7300 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x7280 0x6F00 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x6B80 0x6A00 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x6800 0x6480 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x6100 0x5F00 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x5900 0x5980 + 0x00 0x97 0x32 0x34 0x14 0x16 0x5100 0x8000 0x6700 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x5580 0x8000 0x6880 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x5A00 0x8000 0x6A00 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x5F80 0x8000 0x6B80 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x6580 0x8000 0x6D00 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x6B80 0x8000 0x6E00 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x7100 0x8000 0x6F00 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7600 0x8000 0x7080 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x7D00 0x8000 0x7180 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x8000 0x7A00 0x6F80 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x7280 0x6A80 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x6B80 0x6580 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x6800 0x6080 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x6080 0x5B80 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x5880 0x5680 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x4F80 0x8000 0x6280 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x5480 0x8000 0x6400 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x5900 0x8000 0x6580 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x5E80 0x8000 0x6700 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x6480 0x8000 0x6880 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x6B00 0x8000 0x6980 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x7080 0x8000 0x6B00 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7580 0x8000 0x6C00 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7C00 0x8000 0x6D80 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x8000 0x7A00 0x6B80 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x7280 0x6700 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x6B00 0x6200 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x6800 0x5D80 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x6000 0x5800 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x5880 0x5400 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x4E80 0x8000 0x5E80 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x5300 0x8000 0x6000 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x5800 0x8000 0x6100 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x5D80 0x8000 0x6280 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x6380 0x8000 0x6400 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x6980 0x8000 0x6580 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x6F80 0x8000 0x6700 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7500 0x8000 0x6800 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7B80 0x8000 0x6980 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x8000 0x7A00 0x6800 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x7280 0x6380 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x6B00 0x5E80 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x6800 0x5A00 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x6000 0x5580 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x5380 0x5100 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x4D00 0x8000 0x5A80 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x5200 0x8000 0x5C80 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x5680 0x8000 0x5D80 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x5C80 0x8000 0x5F00 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x6280 0x8000 0x6080 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x6880 0x8000 0x6180 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x6F00 0x8000 0x6300 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7480 0x8000 0x6480 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7B80 0x8000 0x6580 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x8000 0x7A00 0x6480 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x8000 0x7280 0x6000 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x6B00 0x5C00 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x6380 0x5780 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x5B80 0x5300 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x5380 0x4E80 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x4B80 0x8000 0x5780 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x5080 0x8000 0x5900 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x5600 0x8000 0x5A00 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x5B00 0x8000 0x5C00 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x6100 0x8000 0x5D80 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x6800 0x8000 0x5E80 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x6E80 0x8000 0x6000 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7400 0x8000 0x6100 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7B00 0x8000 0x6200 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x8000 0x7A80 0x6180 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x8000 0x7280 0x5D80 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x6B00 0x5900 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x6380 0x5500 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x5B80 0x5080 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x5300 0x4C80 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-vivid-pcc-enable; + somc,mdss-dsi-vivid-pcc-table-size = <226>; + somc,mdss-dsi-vivid-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x5B80 0x7000 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x5E00 0x7000 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x6000 0x7000 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x6200 0x6B80 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x6400 0x6B80 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x6600 0x6B80 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x6880 0x6B80 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x6A80 0x6B80 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x6C80 0x6B80 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x6F00 0x6B00 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x7180 0x6B00 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x7480 0x6B00 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x7780 0x6B00 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x7A00 0x6B00 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x7C80 0x6B00 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x5F80 0x7180 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x6180 0x7180 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x6400 0x7180 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x6580 0x7100 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x6780 0x7100 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x6980 0x7100 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x6C00 0x7100 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x6D80 0x7100 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x7000 0x7080 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x7280 0x7080 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x7500 0x7080 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x7800 0x7080 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x7A80 0x7080 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x7D00 0x7000 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x8000 0x7000 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x6300 0x7300 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x6500 0x7300 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x6700 0x7300 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x6900 0x7280 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x6B00 0x7280 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x6C80 0x7280 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x6E80 0x7280 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x7100 0x7200 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x7380 0x7200 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x7600 0x7200 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x7880 0x7180 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7B00 0x7180 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x7D80 0x7180 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x8000 0x7180 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x8000 0x7000 0x7D80 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x6600 0x7880 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x6800 0x7880 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x6A00 0x7880 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x6C00 0x7800 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x6D80 0x7800 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x6F80 0x7800 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x7200 0x7380 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x7400 0x7380 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x7680 0x7380 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x7900 0x7300 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7B00 0x7300 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x7D80 0x7300 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x8000 0x7280 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x8000 0x7180 0x7D80 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x8000 0x7000 0x7B00 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x6900 0x7A00 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x6B00 0x7A00 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x6C80 0x7980 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x6E80 0x7980 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x7080 0x7980 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x7280 0x7900 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x7500 0x7900 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x7700 0x7880 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x7980 0x7880 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7B80 0x7880 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x7E00 0x7800 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x8000 0x7800 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x8000 0x7280 0x7D80 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x8000 0x7100 0x7B00 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x6B80 0x7800 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x6C00 0x7B80 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x6D80 0x7B80 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x6F00 0x7B00 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x7100 0x7B00 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x7380 0x7A80 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x7580 0x7A80 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x7780 0x7A00 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x7A00 0x7A00 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7C00 0x7A00 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x7E80 0x7980 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x8000 0x7900 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x8000 0x7800 0x7D80 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x8000 0x7280 0x7B00 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x7100 0x7880 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x6B80 0x7580 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x6C00 0x8000 0x7E00 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x6E00 0x8000 0x7E80 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x7080 0x8000 0x7F00 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x7300 0x8000 0x7F80 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x7600 0x8000 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x7800 0x8000 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x7A80 0x7B80 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7C00 0x7B80 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7E80 0x7B00 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x8000 0x7A80 0x7F80 + 0x00 0x65 0x14 0x16 0x20 0x22 0x8000 0x7900 0x7D80 + 0x00 0x66 0x11 0x13 0x20 0x22 0x8000 0x7800 0x7B00 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x7280 0x7900 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x7100 0x7580 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x6B00 0x7300 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x6B80 0x8000 0x7B80 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x6D80 0x8000 0x7C00 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x7000 0x8000 0x7C80 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x7280 0x8000 0x7D00 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x7580 0x8000 0x7D80 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x7800 0x8000 0x7E00 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x7B00 0x8000 0x7E80 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7D80 0x8000 0x7F00 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x8000 0x8000 0x7F80 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x8000 0x7A80 0x7D80 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x8000 0x7900 0x7B80 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x8000 0x7380 0x7900 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7200 0x7600 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x7080 0x7380 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x6B00 0x7080 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x6A80 0x8000 0x7980 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x6D00 0x8000 0x7A00 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x6F80 0x8000 0x7A80 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x7200 0x8000 0x7B00 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x7500 0x8000 0x7B80 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x7800 0x8000 0x7C00 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x7A80 0x8000 0x7C80 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7D00 0x8000 0x7D00 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x8000 0x8000 0x7D80 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x8000 0x7A80 0x7B80 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x7900 0x7980 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7380 0x7680 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7200 0x7400 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x7080 0x7180 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x6A80 0x6E80 + 0x00 0x88 0x32 0x34 0x17 0x19 0x6A00 0x8000 0x7700 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x6C00 0x8000 0x7780 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x6F00 0x8000 0x7800 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x7180 0x8000 0x7900 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x7480 0x8000 0x7980 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x7780 0x8000 0x7A00 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x7A80 0x8000 0x7A80 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7D00 0x8000 0x7B00 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x8000 0x8000 0x7B80 + 0x00 0x91 0x17 0x19 0x17 0x19 0x8000 0x7A80 0x7980 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x7900 0x7780 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7380 0x7480 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7200 0x7200 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x7080 0x6F80 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x6A80 0x6C80 + 0x00 0x97 0x32 0x34 0x14 0x16 0x6900 0x8000 0x7400 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x6C00 0x8000 0x7500 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x6E80 0x8000 0x7580 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x7100 0x8000 0x7600 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x7400 0x8000 0x7700 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x7700 0x8000 0x7800 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x7A00 0x8000 0x7880 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7C80 0x8000 0x7900 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x8000 0x8000 0x7980 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x8000 0x7B00 0x7780 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x7900 0x7500 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7380 0x7300 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x7200 0x7080 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x7000 0x6D80 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x6A00 0x6B00 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x6880 0x8000 0x7200 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x6B80 0x8000 0x7300 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x6E00 0x8000 0x7380 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x7080 0x8000 0x7400 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x7380 0x8000 0x7500 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x7680 0x8000 0x7580 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x7A00 0x8000 0x7600 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7C80 0x8000 0x7700 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7F80 0x8000 0x7780 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x8000 0x7A80 0x7580 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x7900 0x7380 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7380 0x7100 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x7180 0x6E80 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x7000 0x6C00 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x6A00 0x6980 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x6780 0x8000 0x7000 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x6A80 0x8000 0x7100 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x6D00 0x8000 0x7180 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x7000 0x8000 0x7280 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x7300 0x8000 0x7300 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x7680 0x8000 0x7380 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x7980 0x8000 0x7400 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7C00 0x8000 0x7480 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7F80 0x8000 0x7580 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x8000 0x7A80 0x7400 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x7900 0x7180 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7380 0x6F80 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x7180 0x6D00 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x7000 0x6A80 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x6980 0x6800 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x6700 0x8000 0x6E00 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x6A00 0x8000 0x6F00 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x6C80 0x8000 0x6F80 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x6F80 0x8000 0x7080 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x7300 0x8000 0x7100 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x7600 0x8000 0x7200 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x7900 0x8000 0x7280 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7C00 0x8000 0x7300 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7F80 0x8000 0x7380 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x8000 0x7A80 0x7280 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x8000 0x7900 0x7000 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7380 0x6E00 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x7180 0x6B80 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x6B80 0x6900 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x6980 0x6700 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x6600 0x8000 0x6C80 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x6900 0x8000 0x6D00 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x6C00 0x8000 0x6E00 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x6F00 0x8000 0x6E80 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x7280 0x8000 0x6F80 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x7580 0x8000 0x7000 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x7900 0x8000 0x7100 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7B80 0x8000 0x7180 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7F00 0x8000 0x7200 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x8000 0x7A80 0x7100 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x8000 0x7900 0x6E80 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7380 0x6C80 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x7180 0x6A80 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x6B80 0x6780 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x6980 0x6580 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + + somc,mdss-dsi-hdr-pcc-enable; + somc,mdss-dsi-hdr-pcc-table-size = <226>; + somc,mdss-dsi-hdr-pcc-table = < + 0x00 0x01 0x32 0x34 0x32 0x34 0x5A00 0x6B00 0x8000 + 0x00 0x02 0x2F 0x31 0x32 0x34 0x5C80 0x6B00 0x8000 + 0x00 0x03 0x2C 0x2E 0x32 0x34 0x5E00 0x6B00 0x8000 + 0x00 0x04 0x29 0x2B 0x32 0x34 0x6080 0x6B00 0x8000 + 0x00 0x05 0x26 0x28 0x32 0x34 0x6280 0x6B00 0x8000 + 0x00 0x06 0x23 0x25 0x32 0x34 0x6480 0x6A80 0x8000 + 0x00 0x07 0x20 0x22 0x32 0x34 0x6680 0x6A80 0x8000 + 0x00 0x08 0x1D 0x1F 0x32 0x34 0x6880 0x6A80 0x8000 + 0x00 0x09 0x1A 0x1C 0x32 0x34 0x6B00 0x6A80 0x8000 + 0x00 0x0A 0x17 0x19 0x32 0x34 0x6D80 0x6A80 0x8000 + 0x00 0x0B 0x14 0x16 0x32 0x34 0x6F80 0x6A80 0x8000 + 0x00 0x0C 0x11 0x13 0x32 0x34 0x7280 0x6A00 0x8000 + 0x00 0x0D 0x0E 0x10 0x32 0x34 0x7580 0x6A00 0x8000 + 0x00 0x0E 0x0B 0x0D 0x32 0x34 0x7800 0x6A00 0x8000 + 0x00 0x0F 0x08 0x0A 0x32 0x34 0x7B00 0x6A00 0x8000 + 0x00 0x10 0x32 0x34 0x2F 0x31 0x5E00 0x7100 0x8000 + 0x00 0x11 0x2F 0x31 0x2F 0x31 0x6080 0x7080 0x8000 + 0x00 0x12 0x2C 0x2E 0x2F 0x31 0x6200 0x7080 0x8000 + 0x00 0x13 0x29 0x2B 0x2F 0x31 0x6400 0x7080 0x8000 + 0x00 0x14 0x26 0x28 0x2F 0x31 0x6600 0x7080 0x8000 + 0x00 0x15 0x23 0x25 0x2F 0x31 0x6800 0x7000 0x8000 + 0x00 0x16 0x20 0x22 0x2F 0x31 0x6A00 0x7000 0x8000 + 0x00 0x17 0x1D 0x1F 0x2F 0x31 0x6C00 0x7000 0x8000 + 0x00 0x18 0x1A 0x1C 0x2F 0x31 0x6E00 0x7000 0x8000 + 0x00 0x19 0x17 0x19 0x2F 0x31 0x7080 0x6B80 0x8000 + 0x00 0x1A 0x14 0x16 0x2F 0x31 0x7300 0x6B80 0x8000 + 0x00 0x1B 0x11 0x13 0x2F 0x31 0x7600 0x6B80 0x8000 + 0x00 0x1C 0x0E 0x10 0x2F 0x31 0x7880 0x6B80 0x8000 + 0x00 0x1D 0x0B 0x0D 0x2F 0x31 0x7B00 0x6B80 0x8000 + 0x00 0x1E 0x08 0x0A 0x2F 0x31 0x7E80 0x6B80 0x8000 + 0x00 0x1F 0x32 0x34 0x2C 0x2E 0x6180 0x7280 0x8000 + 0x00 0x20 0x2F 0x31 0x2C 0x2E 0x6300 0x7200 0x8000 + 0x00 0x21 0x2C 0x2E 0x2C 0x2E 0x6500 0x7200 0x8000 + 0x00 0x22 0x29 0x2B 0x2C 0x2E 0x6700 0x7200 0x8000 + 0x00 0x23 0x26 0x28 0x2C 0x2E 0x6880 0x7200 0x8000 + 0x00 0x24 0x23 0x25 0x2C 0x2E 0x6B00 0x7180 0x8000 + 0x00 0x25 0x20 0x22 0x2C 0x2E 0x6D00 0x7180 0x8000 + 0x00 0x26 0x1D 0x1F 0x2C 0x2E 0x6F00 0x7180 0x8000 + 0x00 0x27 0x1A 0x1C 0x2C 0x2E 0x7180 0x7100 0x8000 + 0x00 0x28 0x17 0x19 0x2C 0x2E 0x7400 0x7100 0x8000 + 0x00 0x29 0x14 0x16 0x2C 0x2E 0x7680 0x7100 0x8000 + 0x00 0x2A 0x11 0x13 0x2C 0x2E 0x7900 0x7100 0x8000 + 0x00 0x2B 0x0E 0x10 0x2C 0x2E 0x7B80 0x7080 0x8000 + 0x00 0x2C 0x0B 0x0D 0x2C 0x2E 0x7F00 0x7080 0x8000 + 0x00 0x2D 0x08 0x0A 0x2C 0x2E 0x8000 0x6B80 0x7E00 + 0x00 0x2E 0x32 0x34 0x29 0x2B 0x6480 0x7380 0x8000 + 0x00 0x2F 0x2F 0x31 0x29 0x2B 0x6680 0x7380 0x8000 + 0x00 0x30 0x2C 0x2E 0x29 0x2B 0x6880 0x7380 0x8000 + 0x00 0x31 0x29 0x2B 0x29 0x2B 0x6A00 0x7300 0x8000 + 0x00 0x32 0x26 0x28 0x29 0x2B 0x6C00 0x7300 0x8000 + 0x00 0x33 0x23 0x25 0x29 0x2B 0x6D80 0x7300 0x8000 + 0x00 0x34 0x20 0x22 0x29 0x2B 0x7000 0x7280 0x8000 + 0x00 0x35 0x1D 0x1F 0x29 0x2B 0x7200 0x7280 0x8000 + 0x00 0x36 0x1A 0x1C 0x29 0x2B 0x7480 0x7280 0x8000 + 0x00 0x37 0x17 0x19 0x29 0x2B 0x7700 0x7200 0x8000 + 0x00 0x38 0x14 0x16 0x29 0x2B 0x7980 0x7200 0x8000 + 0x00 0x39 0x11 0x13 0x29 0x2B 0x7C00 0x7200 0x8000 + 0x00 0x3A 0x0E 0x10 0x29 0x2B 0x7F00 0x7200 0x8000 + 0x00 0x3B 0x0B 0x0D 0x29 0x2B 0x8000 0x7100 0x7E00 + 0x00 0x3C 0x08 0x0A 0x29 0x2B 0x8000 0x6B80 0x7A80 + 0x00 0x3D 0x32 0x34 0x26 0x28 0x6780 0x7980 0x8000 + 0x00 0x3E 0x2F 0x31 0x26 0x28 0x6900 0x7900 0x8000 + 0x00 0x3F 0x2C 0x2E 0x26 0x28 0x6B00 0x7900 0x8000 + 0x00 0x40 0x29 0x2B 0x26 0x28 0x6D00 0x7900 0x8000 + 0x00 0x41 0x26 0x28 0x26 0x28 0x6E80 0x7880 0x8000 + 0x00 0x42 0x23 0x25 0x26 0x28 0x7080 0x7880 0x8000 + 0x00 0x43 0x20 0x22 0x26 0x28 0x7300 0x7800 0x8000 + 0x00 0x44 0x1D 0x1F 0x26 0x28 0x7500 0x7380 0x8000 + 0x00 0x45 0x1A 0x1C 0x26 0x28 0x7780 0x7380 0x8000 + 0x00 0x46 0x17 0x19 0x26 0x28 0x7980 0x7380 0x8000 + 0x00 0x47 0x14 0x16 0x26 0x28 0x7C00 0x7300 0x8000 + 0x00 0x48 0x11 0x13 0x26 0x28 0x8000 0x7300 0x8000 + 0x00 0x49 0x0E 0x10 0x26 0x28 0x8000 0x7200 0x7D80 + 0x00 0x4A 0x0B 0x0D 0x26 0x28 0x8000 0x7080 0x7A80 + 0x00 0x4B 0x08 0x0A 0x26 0x28 0x8000 0x6B00 0x7800 + 0x00 0x4C 0x32 0x34 0x23 0x25 0x6A00 0x7B00 0x8000 + 0x00 0x4D 0x2F 0x31 0x23 0x25 0x6B80 0x7B00 0x8000 + 0x00 0x4E 0x2C 0x2E 0x23 0x25 0x6D80 0x7A80 0x8000 + 0x00 0x4F 0x29 0x2B 0x23 0x25 0x6F00 0x7A80 0x8000 + 0x00 0x50 0x26 0x28 0x23 0x25 0x7180 0x7A00 0x8000 + 0x00 0x51 0x23 0x25 0x23 0x25 0x7380 0x7980 0x8000 + 0x00 0x52 0x20 0x22 0x23 0x25 0x7580 0x7980 0x8000 + 0x00 0x53 0x1D 0x1F 0x23 0x25 0x7800 0x7980 0x8000 + 0x00 0x54 0x1A 0x1C 0x23 0x25 0x7A00 0x7900 0x8000 + 0x00 0x55 0x17 0x19 0x23 0x25 0x7C80 0x7900 0x8000 + 0x00 0x56 0x14 0x16 0x23 0x25 0x8000 0x7880 0x8000 + 0x00 0x57 0x11 0x13 0x23 0x25 0x8000 0x7300 0x7D80 + 0x00 0x58 0x0E 0x10 0x23 0x25 0x8000 0x7200 0x7A80 + 0x00 0x59 0x0B 0x0D 0x23 0x25 0x8000 0x7080 0x7800 + 0x00 0x5A 0x08 0x0A 0x23 0x25 0x8000 0x6B00 0x7580 + 0x00 0x5B 0x32 0x34 0x20 0x22 0x6B00 0x8000 0x7F00 + 0x00 0x5C 0x2F 0x31 0x20 0x22 0x6D80 0x8000 0x7F80 + 0x00 0x5D 0x2C 0x2E 0x20 0x22 0x6F80 0x8000 0x8000 + 0x00 0x5E 0x29 0x2B 0x20 0x22 0x7200 0x8000 0x8000 + 0x00 0x5F 0x26 0x28 0x20 0x22 0x7400 0x7B80 0x8000 + 0x00 0x60 0x23 0x25 0x20 0x22 0x7600 0x7B00 0x8000 + 0x00 0x61 0x20 0x22 0x20 0x22 0x7880 0x7B00 0x8000 + 0x00 0x62 0x1D 0x1F 0x20 0x22 0x7A00 0x7B00 0x8000 + 0x00 0x63 0x1A 0x1C 0x20 0x22 0x7C80 0x7A80 0x8000 + 0x00 0x64 0x17 0x19 0x20 0x22 0x8000 0x7A80 0x8000 + 0x00 0x65 0x14 0x16 0x20 0x22 0x8000 0x7900 0x7D80 + 0x00 0x66 0x11 0x13 0x20 0x22 0x8000 0x7300 0x7B00 + 0x00 0x67 0x0E 0x10 0x20 0x22 0x8000 0x7200 0x7880 + 0x00 0x68 0x0B 0x0D 0x20 0x22 0x8000 0x7080 0x7580 + 0x00 0x69 0x08 0x0A 0x20 0x22 0x8000 0x6A80 0x7280 + 0x00 0x6A 0x32 0x34 0x1D 0x1F 0x6A80 0x8000 0x7B80 + 0x00 0x6B 0x2F 0x31 0x1D 0x1F 0x6D00 0x8000 0x7C00 + 0x00 0x6C 0x2C 0x2E 0x1D 0x1F 0x6F00 0x8000 0x7C80 + 0x00 0x6D 0x29 0x2B 0x1D 0x1F 0x7180 0x8000 0x7D80 + 0x00 0x6E 0x26 0x28 0x1D 0x1F 0x7480 0x8000 0x7E00 + 0x00 0x6F 0x23 0x25 0x1D 0x1F 0x7700 0x8000 0x7E80 + 0x00 0x70 0x20 0x22 0x1D 0x1F 0x7980 0x8000 0x7F80 + 0x00 0x71 0x1D 0x1F 0x1D 0x1F 0x7C80 0x8000 0x8000 + 0x00 0x72 0x1A 0x1C 0x1D 0x1F 0x8000 0x8000 0x8000 + 0x00 0x73 0x17 0x19 0x1D 0x1F 0x8000 0x7A80 0x7D80 + 0x00 0x74 0x14 0x16 0x1D 0x1F 0x8000 0x7900 0x7B00 + 0x00 0x75 0x11 0x13 0x1D 0x1F 0x8000 0x7300 0x7880 + 0x00 0x76 0x0E 0x10 0x1D 0x1F 0x8000 0x7200 0x7600 + 0x00 0x77 0x0B 0x0D 0x1D 0x1F 0x8000 0x7000 0x7300 + 0x00 0x78 0x08 0x0A 0x1D 0x1F 0x8000 0x6A80 0x7000 + 0x00 0x79 0x32 0x34 0x1A 0x1C 0x6980 0x8000 0x7900 + 0x00 0x7A 0x2F 0x31 0x1A 0x1C 0x6C00 0x8000 0x7980 + 0x00 0x7B 0x2C 0x2E 0x1A 0x1C 0x6E80 0x8000 0x7A00 + 0x00 0x7C 0x29 0x2B 0x1A 0x1C 0x7100 0x8000 0x7A80 + 0x00 0x7D 0x26 0x28 0x1A 0x1C 0x7400 0x8000 0x7B00 + 0x00 0x7E 0x23 0x25 0x1A 0x1C 0x7700 0x8000 0x7B80 + 0x00 0x7F 0x20 0x22 0x1A 0x1C 0x7980 0x8000 0x7C00 + 0x00 0x80 0x1D 0x1F 0x1A 0x1C 0x7C00 0x8000 0x7C80 + 0x00 0x81 0x1A 0x1C 0x1A 0x1C 0x8000 0x8000 0x7D80 + 0x00 0x82 0x17 0x19 0x1A 0x1C 0x8000 0x7A80 0x7B00 + 0x00 0x83 0x14 0x16 0x1A 0x1C 0x8000 0x7900 0x7900 + 0x00 0x84 0x11 0x13 0x1A 0x1C 0x8000 0x7300 0x7680 + 0x00 0x85 0x0E 0x10 0x1A 0x1C 0x8000 0x7180 0x7380 + 0x00 0x86 0x0B 0x0D 0x1A 0x1C 0x8000 0x7000 0x7100 + 0x00 0x87 0x08 0x0A 0x1A 0x1C 0x8000 0x6A00 0x6E80 + 0x00 0x88 0x32 0x34 0x17 0x19 0x6900 0x8000 0x7680 + 0x00 0x89 0x2F 0x31 0x17 0x19 0x6B80 0x8000 0x7700 + 0x00 0x8A 0x2C 0x2E 0x17 0x19 0x6E00 0x8000 0x7780 + 0x00 0x8B 0x29 0x2B 0x17 0x19 0x7080 0x8000 0x7880 + 0x00 0x8C 0x26 0x28 0x17 0x19 0x7380 0x8000 0x7900 + 0x00 0x8D 0x23 0x25 0x17 0x19 0x7680 0x8000 0x7980 + 0x00 0x8E 0x20 0x22 0x17 0x19 0x7980 0x8000 0x7A00 + 0x00 0x8F 0x1D 0x1F 0x17 0x19 0x7C00 0x8000 0x7A80 + 0x00 0x90 0x1A 0x1C 0x17 0x19 0x8000 0x8000 0x7B00 + 0x00 0x91 0x17 0x19 0x17 0x19 0x8000 0x7A80 0x7900 + 0x00 0x92 0x14 0x16 0x17 0x19 0x8000 0x7900 0x7700 + 0x00 0x93 0x11 0x13 0x17 0x19 0x8000 0x7300 0x7400 + 0x00 0x94 0x0E 0x10 0x17 0x19 0x8000 0x7180 0x7180 + 0x00 0x95 0x0B 0x0D 0x17 0x19 0x8000 0x7000 0x6F00 + 0x00 0x96 0x08 0x0A 0x17 0x19 0x8000 0x6A00 0x6C80 + 0x00 0x97 0x32 0x34 0x14 0x16 0x6880 0x8000 0x7380 + 0x00 0x98 0x2F 0x31 0x14 0x16 0x6B00 0x8000 0x7500 + 0x00 0x99 0x2C 0x2E 0x14 0x16 0x6D80 0x8000 0x7580 + 0x00 0x9A 0x29 0x2B 0x14 0x16 0x7000 0x8000 0x7600 + 0x00 0x9B 0x26 0x28 0x14 0x16 0x7300 0x8000 0x7680 + 0x00 0x9C 0x23 0x25 0x14 0x16 0x7600 0x8000 0x7780 + 0x00 0x9D 0x20 0x22 0x14 0x16 0x7900 0x8000 0x7800 + 0x00 0x9E 0x1D 0x1F 0x14 0x16 0x7B80 0x8000 0x7880 + 0x00 0x9F 0x1A 0x1C 0x14 0x16 0x8000 0x8000 0x7900 + 0x00 0xA0 0x17 0x19 0x14 0x16 0x8000 0x7A80 0x7700 + 0x00 0xA1 0x14 0x16 0x14 0x16 0x8000 0x7900 0x7500 + 0x00 0xA2 0x11 0x13 0x14 0x16 0x8000 0x7300 0x7200 + 0x00 0xA3 0x0E 0x10 0x14 0x16 0x8000 0x7180 0x6F80 + 0x00 0xA4 0x0B 0x0D 0x14 0x16 0x8000 0x6B80 0x6D80 + 0x00 0xA5 0x08 0x0A 0x14 0x16 0x8000 0x6980 0x6A80 + 0x00 0xA6 0x32 0x34 0x11 0x13 0x6800 0x8000 0x7180 + 0x00 0xA7 0x2F 0x31 0x11 0x13 0x6A00 0x8000 0x7200 + 0x00 0xA8 0x2C 0x2E 0x11 0x13 0x6D00 0x8000 0x7300 + 0x00 0xA9 0x29 0x2B 0x11 0x13 0x6F80 0x8000 0x7380 + 0x00 0xAA 0x26 0x28 0x11 0x13 0x7280 0x8000 0x7400 + 0x00 0xAB 0x23 0x25 0x11 0x13 0x7580 0x8000 0x7580 + 0x00 0xAC 0x20 0x22 0x11 0x13 0x7900 0x8000 0x7600 + 0x00 0xAD 0x1D 0x1F 0x11 0x13 0x7B80 0x8000 0x7680 + 0x00 0xAE 0x1A 0x1C 0x11 0x13 0x7F00 0x8000 0x7700 + 0x00 0xAF 0x17 0x19 0x11 0x13 0x8000 0x7A80 0x7580 + 0x00 0xB0 0x14 0x16 0x11 0x13 0x8000 0x7900 0x7280 + 0x00 0xB1 0x11 0x13 0x11 0x13 0x8000 0x7300 0x7080 + 0x00 0xB2 0x0E 0x10 0x11 0x13 0x8000 0x7180 0x6E80 + 0x00 0xB3 0x0B 0x0D 0x11 0x13 0x8000 0x6B80 0x6B80 + 0x00 0xB4 0x08 0x0A 0x11 0x13 0x8000 0x6980 0x6900 + 0x00 0xB5 0x32 0x34 0x0E 0x10 0x6700 0x8000 0x6F80 + 0x00 0xB6 0x2F 0x31 0x0E 0x10 0x6980 0x8000 0x7000 + 0x00 0xB7 0x2C 0x2E 0x0E 0x10 0x6C80 0x8000 0x7100 + 0x00 0xB8 0x29 0x2B 0x0E 0x10 0x6F00 0x8000 0x7180 + 0x00 0xB9 0x26 0x28 0x0E 0x10 0x7200 0x8000 0x7280 + 0x00 0xBA 0x23 0x25 0x0E 0x10 0x7580 0x8000 0x7300 + 0x00 0xBB 0x20 0x22 0x0E 0x10 0x7880 0x8000 0x7380 + 0x00 0xBC 0x1D 0x1F 0x0E 0x10 0x7B00 0x8000 0x7400 + 0x00 0xBD 0x1A 0x1C 0x0E 0x10 0x7F00 0x8000 0x7500 + 0x00 0xBE 0x17 0x19 0x0E 0x10 0x8000 0x7A80 0x7300 + 0x00 0xBF 0x14 0x16 0x0E 0x10 0x8000 0x7880 0x7100 + 0x00 0xC0 0x11 0x13 0x0E 0x10 0x8000 0x7300 0x6E80 + 0x00 0xC1 0x0E 0x10 0x0E 0x10 0x8000 0x7180 0x6C80 + 0x00 0xC2 0x0B 0x0D 0x0E 0x10 0x8000 0x6B80 0x6A00 + 0x00 0xC3 0x08 0x0A 0x0E 0x10 0x8000 0x6980 0x6780 + 0x00 0xC4 0x32 0x34 0x0B 0x0D 0x6600 0x8000 0x6E00 + 0x00 0xC5 0x2F 0x31 0x0B 0x0D 0x6880 0x8000 0x6E00 + 0x00 0xC6 0x2C 0x2E 0x0B 0x0D 0x6C00 0x8000 0x6F00 + 0x00 0xC7 0x29 0x2B 0x0B 0x0D 0x6E80 0x8000 0x6F80 + 0x00 0xC8 0x26 0x28 0x0B 0x0D 0x7180 0x8000 0x7080 + 0x00 0xC9 0x23 0x25 0x0B 0x0D 0x7500 0x8000 0x7100 + 0x00 0xCA 0x20 0x22 0x0B 0x0D 0x7800 0x8000 0x7200 + 0x00 0xCB 0x1D 0x1F 0x0B 0x0D 0x7B00 0x8000 0x7280 + 0x00 0xCC 0x1A 0x1C 0x0B 0x0D 0x7F00 0x8000 0x7300 + 0x00 0xCD 0x17 0x19 0x0B 0x0D 0x8000 0x7A80 0x7180 + 0x00 0xCE 0x14 0x16 0x0B 0x0D 0x8000 0x7880 0x6F80 + 0x00 0xCF 0x11 0x13 0x0B 0x0D 0x8000 0x7300 0x6D80 + 0x00 0xD0 0x0E 0x10 0x0B 0x0D 0x8000 0x7100 0x6B00 + 0x00 0xD1 0x0B 0x0D 0x0B 0x0D 0x8000 0x6B00 0x6900 + 0x00 0xD2 0x08 0x0A 0x0B 0x0D 0x8000 0x6900 0x6600 + 0x00 0xD3 0x32 0x34 0x08 0x0A 0x6580 0x8000 0x6C00 + 0x00 0xD4 0x2F 0x31 0x08 0x0A 0x6880 0x8000 0x6D00 + 0x00 0xD5 0x2C 0x2E 0x08 0x0A 0x6B00 0x8000 0x6D80 + 0x00 0xD6 0x29 0x2B 0x08 0x0A 0x6E00 0x8000 0x6E00 + 0x00 0xD7 0x26 0x28 0x08 0x0A 0x7100 0x8000 0x6E80 + 0x00 0xD8 0x23 0x25 0x08 0x0A 0x7480 0x8000 0x6F80 + 0x00 0xD9 0x20 0x22 0x08 0x0A 0x7800 0x8000 0x7000 + 0x00 0xDA 0x1D 0x1F 0x08 0x0A 0x7A80 0x8000 0x7080 + 0x00 0xDB 0x1A 0x1C 0x08 0x0A 0x7E80 0x8000 0x7180 + 0x00 0xDC 0x17 0x19 0x08 0x0A 0x8000 0x7A80 0x7000 + 0x00 0xDD 0x14 0x16 0x08 0x0A 0x8000 0x7880 0x6E00 + 0x00 0xDE 0x11 0x13 0x08 0x0A 0x8000 0x7300 0x6C00 + 0x00 0xDF 0x0E 0x10 0x08 0x0A 0x8000 0x7100 0x6980 + 0x00 0xE0 0x0B 0x0D 0x08 0x0A 0x8000 0x6B00 0x6700 + 0x00 0xE1 0x08 0x0A 0x08 0x0A 0x8000 0x6900 0x6500 + 0xFF 0x00 0x0E 0x38 0x0C 0x2F 0x8000 0x8000 0x8000>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-poplar.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-poplar.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..116c41facd4510408cb7e7cd82f0d6174f6cb012 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-poplar.dtsi @@ -0,0 +1,415 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include "dsi-panel-poplar-id6_pcc.dtsi" +#include "dsi-panel-poplar-id9_pcc.dtsi" + +&mdss_mdp { + /* JDI ID6 */ + dsi_6: somc,6_panel { + qcom,mdss-dsi-panel-name = "6"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-front-porch = <56>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-v-front-porch = <227>; + qcom,mdss-pan-physical-width-dimension = <64>; + qcom,mdss-pan-physical-height-dimension = <114>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-underflow-color = <0x0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 08 C2 01 07 80 04 00 04 F0 + 29 01 00 00 00 00 03 C4 70 22 + 29 01 00 00 00 00 15 C6 53 2E 2E 05 45 00 00 00 00 00 00 42 0F 00 00 00 00 04 10 06 + 29 01 00 00 00 00 0E EC 64 DC EC 3B 52 00 0B 0B 13 15 68 0B B5 + 29 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 36 00 + 39 01 00 00 00 00 02 3A 77 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 07 7F + 39 01 00 00 00 00 03 44 00 00 + 39 01 00 00 78 00 01 11]; + qcom,mdss-dsi-post-panel-on-command = [ + 39 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = [ + 39 01 00 00 14 00 01 28 + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 0E EC 64 DC EC 3B 52 00 0B 0B 13 15 68 0B 95 + 29 01 00 00 00 00 02 B0 03 + 39 01 00 00 78 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [00 1B 06 06 0B 11 05 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_hybrid_incell>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14940 15790 33800 15700 10950 33800 7450 2300>; + qcom,mdss-dsi-panel-peak-brightness = <7000000>; + qcom,mdss-dsi-panel-blackness-level = <4646>; + + + qcom,mdss-dsi-panel-clockrate = <899000000>; + + somc,lcd-id-adc = <565000 653000>; + somc,mdss-dsi-master; + somc,pw-on-rst-seq = <0 15>, <1 16>, <0 15>, <1 20>; + somc,pw-off-rst-b-seq = <0 11>; + somc,pw-wait-after-on-vdd = <0>; + somc,pw-wait-after-on-vddio = <1>; + somc,pw-wait-after-on-vsp = <1>; + somc,pw-wait-after-on-vsn = <0>; + somc,pw-wait-after-off-vdd = <0>; + somc,pw-wait-after-off-vddio = <1>; + somc,pw-wait-after-off-vsp = <8>; + somc,pw-wait-after-off-vsn = <8>; + somc,pw-wait-after-on-touch-avdd = <1>; + somc,pw-wait-after-on-touch-vddio = <0>; + somc,pw-wait-after-on-touch-reset = <0>; + somc,pw-wait-after-on-touch-int-n = <10>; + somc,pw-wait-after-off-touch-avdd = <0>; + somc,pw-wait-after-off-touch-vddio = <0>; + somc,pw-wait-after-off-touch-reset = <11>; + somc,pw-wait-after-off-touch-int-n = <0>; + somc,pw-down-period = <300>; + + somc,lab-output-voltage = <5600000>; + somc,ibb-output-voltage = <5600000>; + somc,qpnp-lab-limit-maximum-current = <200>; + somc,qpnp-ibb-limit-maximum-current = <800>; + somc,qpnp-lab-max-precharge-time = <500>; + somc,qpnp-lab-soft-start = <800>; + somc,qpnp-ibb-discharge-resistor = <300>; + somc,qpnp-lab-pull-down-enable; + somc,qpnp-lab-full-pull-down; + somc,qpnp-ibb-pull-down-enable; + somc,qpnp-ibb-full-pull-down; + + somc,ewu-wait-after-touch-reset = <40>; + + somc,change-fps-enable; + somc,change-fps-panel-type = "hybrid_incell_type"; + somc,change-fps-panel-mode = "dynamic_mode"; + somc,change-fps-command = + [29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 08 C2 01 07 80 04 00 04 F0]; + somc,driver-ic-rtn = <83>; + somc,driver-ic-vdisp = <1920>; + somc,driver-ic-vtouch = <6818000>; + somc,driver-ic-mclk = <61539>; + somc,change-fps-send-pos = <2 4>; + somc,change-fps-send-byte = <4>; + somc,change-fps-porch-mask-pos = <3>; + somc,change-fps-porch-mask = <0xF0>; + somc,change-fps-porch-range = <4 511>; + + somc,mdss-dsi-disp-on-in-hs = <0>; + somc,mdss-dsi-wait-time-before-post-on-cmd = <0>; + }; + + /* Sharp ID9 */ + dsi_9: somc,9_panel { + qcom,mdss-dsi-panel-name = "9"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-front-porch = <56>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-v-front-porch = <227>; + qcom,mdss-pan-physical-width-dimension = <64>; + qcom,mdss-pan-physical-height-dimension = <114>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-underflow-color = <0x0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 35 00 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-post-panel-on-command = [ + 05 01 00 00 00 00 01 11 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 01 28 + 05 01 00 00 78 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [00 1B 06 06 0B 11 05 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_full_incell>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14940 15790 33800 15700 10950 33800 7450 2300>; + qcom,mdss-dsi-panel-peak-brightness = <7000000>; + qcom,mdss-dsi-panel-blackness-level = <4646>; + + + qcom,mdss-dsi-panel-clockrate = <899000000>; + + somc,lcd-id-adc = <0 57000>; + somc,mdss-dsi-master; + somc,pw-on-rst-seq = <0 15>, <1 20>; + somc,pw-off-rst-b-seq = <0 11>; + somc,pw-wait-after-on-vdd = <0>; + somc,pw-wait-after-on-vddio = <10>; + somc,pw-wait-after-on-vsp = <10>; + somc,pw-wait-after-on-vsn = <0>; + somc,pw-wait-after-off-vdd = <0>; + somc,pw-wait-after-off-vddio = <0>; + somc,pw-wait-after-off-vsp = <8>; + somc,pw-wait-after-off-vsn = <8>; + somc,pw-wait-after-on-touch-vddio = <0>; + somc,pw-wait-after-on-touch-reset = <0>; + somc,pw-wait-after-on-touch-int-n = <10>; + somc,pw-wait-after-off-touch-vddio = <0>; + somc,pw-wait-after-off-touch-reset = <11>; + somc,pw-wait-after-off-touch-int-n = <0>; + somc,pw-down-period = <300>; + + somc,lab-output-voltage = <5600000>; + somc,ibb-output-voltage = <5600000>; + somc,qpnp-lab-limit-maximum-current = <200>; + somc,qpnp-ibb-limit-maximum-current = <800>; + somc,qpnp-lab-max-precharge-time = <500>; + somc,qpnp-lab-soft-start = <800>; + somc,qpnp-ibb-discharge-resistor = <300>; + somc,qpnp-lab-pull-down-enable; + somc,qpnp-lab-full-pull-down; + somc,qpnp-ibb-pull-down-enable; + somc,qpnp-ibb-full-pull-down; + + somc,ewu-rst-seq = <0 2>, <1 5>; + somc,ewu-wait-after-touch-reset = <0>; + + somc,change-fps-enable; + somc,change-fps-panel-type = "full_incell_type"; + somc,change-fps-panel-mode = "dynamic_mode"; + somc,change-fps-command = + [29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 02 C6 59]; + somc,driver-ic-total-porch = <11>; + somc,driver-ic-vdisp = <1920>; + somc,driver-ic-rclk = <14000000>; + somc,driver-ic-vtp = <682>; + somc,change-fps-rtn-pos = <2 1>; + }; + + /* Default */ + dsi_default_panel: somc,default_cmd_panel { + qcom,mdss-dsi-panel-name = "default"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-front-porch = <56>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-v-front-porch = <227>; + qcom,mdss-pan-physical-width-dimension = <64>; + qcom,mdss-pan-physical-height-dimension = <114>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-underflow-color = <0x0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 08 C2 01 07 80 04 00 04 F0 + 29 01 00 00 00 00 03 C4 70 22 + 29 01 00 00 00 00 15 C6 53 2E 2E 05 45 00 00 00 00 00 00 42 0F 00 00 00 00 04 10 06 + 29 01 00 00 00 00 0E EC 64 DC EC 3B 52 00 0B 0B 13 15 68 0B B5 + 29 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 36 00 + 39 01 00 00 00 00 02 3A 77 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 07 7F + 39 01 00 00 00 00 03 44 00 00 + 39 01 00 00 78 00 01 11]; + qcom,mdss-dsi-post-panel-on-command = [ + 39 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = [ + 39 01 00 00 14 00 01 28 + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 0E EC 64 DC EC 3B 52 00 0B 0B 13 15 68 0B 95 + 29 01 00 00 00 00 02 B0 03 + 39 01 00 00 78 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [00 1B 06 06 0B 11 05 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_hybrid_incell>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14940 15790 33800 15700 10950 33800 7450 2300>; + qcom,mdss-dsi-panel-peak-brightness = <7000000>; + qcom,mdss-dsi-panel-blackness-level = <4646>; + + qcom,mdss-dsi-panel-clockrate = <899000000>; + + somc,lcd-id-adc = <0 0x7fffffff>; + somc,mdss-dsi-master; + somc,pw-on-rst-seq = <0 15>, <1 16>, <0 15>, <1 20>; + somc,pw-off-rst-b-seq = <0 11>; + somc,pw-wait-after-on-vdd = <0>; + somc,pw-wait-after-on-vddio = <1>; + somc,pw-wait-after-on-vsp = <1>; + somc,pw-wait-after-on-vsn = <0>; + somc,pw-wait-after-off-vdd = <0>; + somc,pw-wait-after-off-vddio = <1>; + somc,pw-wait-after-off-vsp = <8>; + somc,pw-wait-after-off-vsn = <8>; + somc,pw-wait-after-on-touch-avdd = <1>; + somc,pw-wait-after-on-touch-vddio = <0>; + somc,pw-wait-after-on-touch-reset = <0>; + somc,pw-wait-after-on-touch-int-n = <10>; + somc,pw-wait-after-off-touch-avdd = <0>; + somc,pw-wait-after-off-touch-vddio = <0>; + somc,pw-wait-after-off-touch-reset = <11>; + somc,pw-wait-after-off-touch-int-n = <0>; + somc,pw-down-period = <300>; + + somc,lab-output-voltage = <5600000>; + somc,ibb-output-voltage = <5600000>; + somc,qpnp-lab-limit-maximum-current = <200>; + somc,qpnp-ibb-limit-maximum-current = <800>; + somc,qpnp-lab-max-precharge-time = <500>; + somc,qpnp-lab-soft-start = <800>; + somc,qpnp-ibb-discharge-resistor = <300>; + somc,qpnp-lab-pull-down-enable; + somc,qpnp-lab-full-pull-down; + somc,qpnp-ibb-pull-down-enable; + somc,qpnp-ibb-full-pull-down; + + somc,ewu-wait-after-touch-reset = <40>; + + somc,mdss-dsi-disp-on-in-hs = <0>; + somc,mdss-dsi-wait-time-before-post-on-cmd = <0>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi index ff3b7b80c449d33e66a20b300205d909450de394..51a225b82f47497b0d99fcc835519807718a38cc 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -54,8 +54,6 @@ qcom,ulps-enabled; qcom,dcs-cmd-by-left; qcom,mdss-dsi-tx-eot-append; - qcom,mdss-pan-physical-width-dimension = <68>; - qcom,mdss-pan-physical-height-dimension = <121>; qcom,adjust-timer-wakeup-ms = <1>; qcom,mdss-dsi-on-command = [ diff --git a/arch/arm/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi index 933746b8abe75838858ee4607dd305943cad4e4f..02c87067f21233dc5949f1967a214371cf0700b1 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -46,8 +46,6 @@ qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; qcom,mdss-dsi-tx-eot-append; - qcom,mdss-pan-physical-width-dimension = <68>; - qcom,mdss-pan-physical-height-dimension = <121>; qcom,adjust-timer-wakeup-ms = <1>; qcom,mdss-dsi-on-command = [ diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-lilac-send-4335mv-2647mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-lilac-send-4335mv-2647mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..56765d2e53b002a7e3d04654a96213333e9efd1a --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-lilac-send-4335mv-2647mah.dtsi @@ -0,0 +1,87 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +qcom,send_2647mah { + qcom,max-voltage-uv = <4335000>; + qcom,fg-cc-cv-threshold-mv = <4325>; + qcom,fastchg-current-ma = <2025>; + qcom,batt-id-kohm = <330>; + qcom,battery-beta = <4050>; + qcom,battery-type = "1308-1851-2"; + qcom,checksum = <0xF252>; + qcom,gui-version = "PMI8998GUI - 2.0.0.55"; + qcom,fg-profile-data = [ + 5A 1F EE 05 + 0D 0A 7B FD + AD 1C 21 FB + E9 06 05 EC + 47 18 95 22 + 33 3C F5 4B + 53 00 00 00 + 0F 00 00 00 + 00 00 62 C2 + F8 07 D8 C2 + 2E 00 08 00 + F1 DC 1B DD + 5D FC 22 F3 + 81 06 AF 02 + 59 FC 13 3A + 18 06 09 20 + 27 00 14 00 + FF 1B 96 01 + 2A 07 96 F3 + 77 1C 25 03 + 50 0C 61 0B + 97 18 D5 22 + 96 45 F8 52 + 81 00 00 00 + 0D 00 00 00 + 00 00 29 C5 + B7 C3 B6 CD + 26 00 00 00 + 37 EA 1B DD + 9B FC C2 F2 + E1 FD 30 03 + 3B D4 8E 12 + 99 33 CC FF + 07 10 00 00 + 9D 0A 5C 45 + 26 00 40 00 + 89 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-lilac-send-4357mv-2688mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-lilac-send-4357mv-2688mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..65456441f01c2dd8c9d728614d875be2455ae5d0 --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-lilac-send-4357mv-2688mah.dtsi @@ -0,0 +1,87 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +qcom,send_2688mah { + qcom,max-voltage-uv = <4357000>; + qcom,fg-cc-cv-threshold-mv = <4347>; + qcom,fastchg-current-ma = <2025>; + qcom,batt-id-kohm = <330>; + qcom,battery-beta = <4050>; + qcom,battery-type = "1308-1851-1"; + qcom,checksum = <0x98E0>; + qcom,gui-version = "PMI8998GUI - 2.0.0.55"; + qcom,fg-profile-data = [ + 80 1F B7 05 + 40 0A 8F 06 + A5 1C 67 FB + D3 FC D7 CC + 67 18 8C 22 + 3D 3C E3 4B + 56 00 00 00 + 0F 00 00 00 + 00 00 EC BA + 33 CC 17 CA + 2E 00 08 00 + 15 DC 79 DD + 3B 06 F7 F2 + FB FC 89 02 + 23 F3 B3 3B + 15 06 09 20 + 27 00 14 00 + A3 1B F9 01 + 53 FD 27 01 + 6E 1C 4D 03 + FE 15 D0 0B + 9E 18 C5 22 + B4 45 B9 52 + 7D 00 00 00 + 0D 00 00 00 + 00 00 29 C5 + 19 C3 B6 CD + 26 00 00 00 + 3F EA 79 DD + 81 FC F9 F2 + E2 06 06 03 + FB 07 B0 12 + 99 33 CC FF + 07 10 00 00 + CD 0A B6 45 + 26 00 40 00 + 81 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-lilac-send-4380mv-2729mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-lilac-send-4380mv-2729mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..15a1af1d3d6be6c5692527a1ea134fe52cf3fd79 --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-lilac-send-4380mv-2729mah.dtsi @@ -0,0 +1,87 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +qcom,send_2729mah { + qcom,max-voltage-uv = <4380000>; + qcom,fg-cc-cv-threshold-mv = <4370>; + qcom,fastchg-current-ma = <2025>; + qcom,batt-id-kohm = <330>; + qcom,battery-beta = <4050>; + qcom,battery-type = "1308-1851-0"; + qcom,checksum = <0x4442>; + qcom,gui-version = "PMI8998GUI - 2.0.0.55"; + qcom,fg-profile-data = [ + 89 1F A5 05 + 5B 0A EB FC + AD 1C AC 01 + E5 FC 77 D3 + 6C 18 92 22 + 30 3C F0 4B + 62 00 00 00 + 0F 00 00 00 + 00 00 E5 AB + B6 CC 58 CA + 2D 00 08 00 + FE DC EC DC + 8B FC D1 F2 + A7 06 8E 02 + 41 EB 56 3A + 16 06 09 20 + 27 00 14 00 + A0 1F C1 05 + 3E 0A 95 06 + 74 1C 45 03 + 0E 0C B0 0B + B3 18 B5 22 + CE 45 85 52 + 5E 00 00 00 + 0C 00 00 00 + 00 00 29 C5 + 27 C3 B6 CD + 26 00 00 00 + 4C EA EC DC + 46 06 F1 F2 + 97 FD 9E 02 + 46 D2 FC 12 + 99 33 CC FF + 07 10 00 00 + 04 0B 14 46 + 26 00 40 00 + 80 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-send-4335mv-2647mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-send-4335mv-2647mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..eb270db7d6768d61e6b5f2f8757755dfb3c10dac --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-send-4335mv-2647mah.dtsi @@ -0,0 +1,87 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +qcom,send_2647mah { + qcom,max-voltage-uv = <4335000>; + qcom,fg-cc-cv-threshold-mv = <4325>; + qcom,fastchg-current-ma = <2025>; + qcom,batt-id-kohm = <330>; + qcom,battery-beta = <4050>; + qcom,battery-type = "1307-0625-2"; + qcom,checksum = <0x488B>; + qcom,gui-version = "PMI8998GUI - 2.0.0.55"; + qcom,fg-profile-data = [ + 6B 1F D4 05 + 22 0A A7 06 + C0 1C 15 01 + 77 01 D3 0D + 8C 18 96 22 + 19 3C 12 52 + 58 00 00 00 + 0E 00 00 00 + 00 00 9D C3 + 4F D5 E8 CA + 2E 00 08 00 + 6D E5 C5 D5 + 7F 05 56 01 + DC 04 12 03 + FE 07 40 1B + 44 06 09 20 + 27 00 14 00 + 90 1A 1C 03 + 11 05 D6 01 + 80 1C 16 03 + 70 0C 40 0B + 94 18 DA 22 + 92 45 FA 52 + 85 00 00 00 + 0D 00 00 00 + 00 00 26 CD + 0C C3 D3 C5 + 24 00 00 00 + B1 E3 C5 D5 + D9 05 05 01 + 29 FD F1 03 + AD 06 A9 12 + 99 33 CC FF + 07 10 00 00 + 80 0A 5C 45 + 24 00 40 00 + BC 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-send-4357mv-2688mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-send-4357mv-2688mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..cb9bbfacebd8c0a0b7ea456b3e3cc36590a343da --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-send-4357mv-2688mah.dtsi @@ -0,0 +1,87 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +qcom,send_2688mah { + qcom,max-voltage-uv = <4357000>; + qcom,fg-cc-cv-threshold-mv = <4347>; + qcom,fastchg-current-ma = <2025>; + qcom,batt-id-kohm = <330>; + qcom,battery-beta = <4050>; + qcom,battery-type = "1307-0625-1"; + qcom,checksum = <0xF300>; + qcom,gui-version = "PMI8998GUI - 2.0.0.55"; + qcom,fg-profile-data = [ + C3 1A 8D 02 + 2B FC AB FA + 71 1C 61 02 + BB 0D FE 03 + 19 18 02 23 + 6F 45 22 53 + 83 00 00 00 + 0E 00 00 00 + 00 00 A4 C2 + 97 D5 2A CB + 2D 00 08 00 + 50 DC E5 DD + 92 05 83 FA + 17 05 3C 03 + 63 DD 15 1B + 43 06 09 20 + 27 00 14 00 + 34 1B 61 02 + 2E 06 54 01 + 82 1C 17 03 + 6A 0C 52 0B + E5 18 72 22 + 53 3C E2 4B + 84 00 00 00 + 0D 00 00 00 + 00 00 40 CC + 75 C3 0D A2 + 25 00 00 00 + F5 E3 E5 DD + D6 05 09 01 + C9 FC 67 03 + 86 06 10 13 + 99 33 CC FF + 07 10 00 00 + AF 0A B6 45 + 25 00 40 00 + C0 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-send-4380mv-2650mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-send-4380mv-2650mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..04d5696797b3b870b0124242235b5d01758a45a3 --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-send-4380mv-2650mah.dtsi @@ -0,0 +1,87 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +qcom,send_2650mah { + qcom,max-voltage-uv = <4380000>; + qcom,fg-cc-cv-threshold-mv = <4370>; + qcom,fastchg-current-ma = <2025>; + qcom,batt-id-kohm = <330>; + qcom,battery-beta = <4050>; + qcom,battery-type = "1307-0625-0"; + qcom,checksum = <0xE818>; + qcom,gui-version = "PMI8998GUI - 2.0.0.55"; + qcom,fg-profile-data = [ + 5F 1F D5 05 + 36 0A 98 06 + AF 1C E9 FA + 6C E4 EF 05 + 61 18 9C 22 + 13 3C 0F 52 + 50 00 00 00 + 0F 00 00 00 + 00 00 04 00 + 4B D5 A0 CA + 2C 00 08 00 + 41 DC 8F DD + 9E 05 6D FA + 4E 05 5B 03 + 17 D4 D0 1A + 43 06 09 20 + 27 00 14 00 + A8 1B E2 01 + D9 FD 02 01 + 7A 1C 44 03 + 07 0C D0 0B + 9F 18 D1 22 + A9 45 C3 52 + 83 00 00 00 + 0D 00 00 00 + 00 00 DF D5 + 89 BB EB C3 + 24 00 00 00 + 29 EA 8F DD + DE 05 FF 00 + 7D 06 96 03 + E1 E2 11 1A + AE 33 CC FF + 07 10 00 00 + E8 0A 14 46 + 24 00 40 00 + BD 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-tdk-4380mv-2650mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-tdk-4380mv-2650mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b318300afc7e977e36ebdd7670536130d0d0e774 --- /dev/null +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-poplar-tdk-4380mv-2650mah.dtsi @@ -0,0 +1,87 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +qcom,tdk_2650mah { + qcom,max-voltage-uv = <4000000>; + qcom,fg-cc-cv-threshold-mv = <3990>; + qcom,fastchg-current-ma = <525>; + qcom,batt-id-kohm = <15>; + qcom,battery-beta = <4050>; + qcom,battery-type = "TDK(Restricted)"; + qcom,checksum = <0x2596>; + qcom,gui-version = "PMI8998GUI - 2.0.0.54"; + qcom,fg-profile-data = [ + 92 1F 9E 05 + 6C 0A 52 06 + 4C 1D 93 E2 + 28 0A 2A 0C + 85 18 3C 23 + 1B 45 8A 53 + 5B 00 00 00 + 0E 00 00 00 + 00 00 EE C5 + D7 CD 9D C3 + 23 00 08 00 + CD DB 4A E4 + 97 06 D9 EB + 07 F3 35 12 + 13 07 6C 2B + 19 06 09 20 + 27 00 14 00 + A6 20 8D 04 + 2B 0B A8 05 + 26 1D 0B FB + A9 06 55 F5 + AE 19 55 22 + 53 3C D7 4B + 60 00 00 00 + 0D 00 00 00 + 00 00 74 CD + 4E BA BD BB + 1D 00 00 00 + C4 EA 4A E4 + DA 06 8B EA + D2 E3 66 0A + F6 EC 71 1A + 99 33 CC FF + 07 10 00 00 + DA 0A 14 46 + 1D 00 40 00 + CC 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi index 460e7e76ac4d1ecc4088c51c594e4d158d242719..93aeef07cfe0cc978a17be752864fd47db4d95cc 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi @@ -24,7 +24,6 @@ compatible = "qcom,qpnp-revid"; reg = <0x100 0x100>; qcom,fab-id-valid; - qcom,tp-rev-valid; }; pm660_misc: qcom,misc@900 { diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi index 075eaef2125453808195ae1f9f4fc2e28bdddcd7..0f18ba5c94c74de96e0dfcaf8dae0259a1075de2 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi @@ -250,8 +250,9 @@ <0xd900 0x100>; reg-names = "qpnp-wled-ctrl-base", "qpnp-wled-sink-base"; - interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "ovp-irq"; + interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ovp-irq", "sc-irq"; linux,name = "wled"; linux,default-trigger = "bkl-trigger"; qcom,fdbk-output = "auto"; @@ -267,9 +268,9 @@ qcom,fs-curr-ua = <25000>; qcom,cons-sync-write-delay-us = <1000>; qcom,led-strings-list = [00 01 02]; + qcom,en-ext-pfet-sc-pro; qcom,loop-auto-gm-en; qcom,pmic-revid = <&pm660l_revid>; - qcom,auto-calibration-enable; status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index 147b537eba33ba0bfc956b76f6c9c89be3c5b477..684f6cf9b389aeea773ad3d8e8395515d64c2a98 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -634,7 +634,6 @@ qcom,en-ext-pfet-sc-pro; qcom,pmic-revid = <&pmi8998_revid>; qcom,loop-auto-gm-en; - qcom,auto-calibration-enable; status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/msm-rdbg.dtsi b/arch/arm/boot/dts/qcom/msm-rdbg.dtsi index 6de1a8e2fb7e4655c2fc58710b3c0e66c8e36813..d0c91f9e72aebd1cd5291b8e87d742c256ad1af0 100644 --- a/arch/arm/boot/dts/qcom/msm-rdbg.dtsi +++ b/arch/arm/boot/dts/qcom/msm-rdbg.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -72,35 +72,4 @@ compatible = "qcom,smp2pgpio_client_rdbg_1_out"; gpios = <&smp2pgpio_rdbg_1_out 0 0>; }; - - smp2pgpio_rdbg_5_in: qcom,smp2pgpio-rdbg-5-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "rdbg"; - qcom,remote-pid = <5>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_client_rdbg_5_in { - compatible = "qcom,smp2pgpio_client_rdbg_5_in"; - gpios = <&smp2pgpio_rdbg_5_in 0 0>; - }; - - smp2pgpio_rdbg_5_out: qcom,smp2pgpio-rdbg-5-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "rdbg"; - qcom,remote-pid = <5>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_client_rdbg_5_out { - compatible = "qcom,smp2pgpio_client_rdbg_5_out"; - gpios = <&smp2pgpio_rdbg_5_out 0 0>; - }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index 2dc5c919190c228bb5d0e802b9c0d3f7b887924c..3b55215c7e5da9399082ed76da35192d64987c33 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -547,7 +547,7 @@ #include "msm8996-sde-display.dtsi" -&sde_kms { +&mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; qcom,sde-plane-id-map { qcom,sde-plane-id@0 { @@ -869,9 +869,6 @@ qcom,ntn-rst-delay-msec = <100>; qcom,ntn-rc-num = <1>; - qcom,ntn-bus-num = <1>; - qcom,ntn-mdio-bus-id = <1>; - qcom,ntn-phy-addr = <7>; qcom,msm-bus,name = "ntn"; qcom,msm-bus,num-cases = <2>; @@ -1016,10 +1013,6 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, - <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, - <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, - <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, - <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -1038,10 +1031,6 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", - "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", - "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", - "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", - "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", @@ -1249,7 +1238,7 @@ qcom,vin-sel = <2>; /* 1.8 */ qcom,out-strength = <1>; qcom,src-sel = <0>; /* GPIO */ - qcom,master-en = <1>; /* Enable GPIO */ + qcom,master-en = <0>; /* Disable GPIO */ status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi index 1d5e3035afd09c02175f9f9b7e11d8433ccc4d8d..4fe6f0d67fbe5cefafa626a056489d513588023c 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -333,7 +333,7 @@ }; }; -&sde_kms { +&mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; qcom,sde-plane-id-map { qcom,sde-plane-id@0 { @@ -635,8 +635,6 @@ qcom,ntn-rst-delay-msec = <100>; qcom,ntn-rc-num = <1>; qcom,ntn-bus-num = <1>; - qcom,ntn-mdio-bus-id = <1>; - qcom,ntn-phy-addr = <7>; qcom,msm-bus,name = "ntn"; qcom,msm-bus,num-cases = <2>; @@ -651,7 +649,6 @@ qcom,ntn-rst-delay-msec = <100>; qcom,ntn-rc-num = <2>; qcom,ntn-bus-num = <1>; - qcom,ntn-mdio-bus-id = <2>; qcom,msm-bus,name = "ntn"; qcom,msm-bus,num-cases = <2>; @@ -838,10 +835,6 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, - <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, - <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, - <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, - <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -860,10 +853,6 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", - "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", - "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", - "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", - "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", diff --git a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi index c8898ec01992155f58dd8a40d2dd7b955d1391c5..d3ea51268590dc456e20c4f7e827d8c7908f1eb9 100644 --- a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi @@ -538,10 +538,6 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, - <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, - <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, - <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, - <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -560,10 +556,6 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", - "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", - "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", - "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", - "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", diff --git a/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi index 0bd9b02f3d2ed43174a57cc02de67748707e15ee..ab10a71d1fd76322a077a012f84ba6e1bbdc6a92 100644 --- a/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 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 @@ -343,7 +343,7 @@ qcom,mdss-pref-prim-intf = "dsi"; }; -&sde_hdmi { +&mdss_hdmi { status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi index 316859a65801f24bcb87d3face83cb60aea9ba33..ff128acb376a1f896387ccfca21c7a7d60d4de81 100644 --- a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi @@ -1449,7 +1449,7 @@ }; cnss_pins { - cnss_bootstrap_active: cnss_bootstrap_active { + cnss_default: cnss_default { mux { pins = "gpio46"; function = "gpio"; @@ -1458,20 +1458,6 @@ config { pins = "gpio46"; drive-strength = <16>; - output-high; - bias-pull-up; - }; - }; - cnss_bootstrap_sleep: cnss_bootstrap_sleep { - mux { - pins = "gpio46"; - function = "gpio"; - }; - - config { - pins = "gpio46"; - drive-strength = <2>; - output-low; bias-pull-down; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi index 936dfd4d1cb2eec15c23f608f9dc53906b16fd36..e1921c3baeb3b4c030f4f53bdce500eeb635878a 100644 --- a/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi @@ -1918,13 +1918,6 @@ gpio = <&pm8994_gpios 9 0>; }; - wlan_en_vreg: wlan_en_vreg { - compatible = "regulator-fixed"; - regulator-name = "wlan_en_vreg"; - enable-active-high; - gpio = <&pm8994_gpios 8 0>; - }; - hl7509_en_vreg: hl7509_en_vreg { compatible = "regulator-fixed"; regulator-name = "hl7509_en_vreg"; diff --git a/arch/arm/boot/dts/qcom/msm8996-sde-display.dtsi b/arch/arm/boot/dts/qcom/msm8996-sde-display.dtsi index 1c81bc433374ce89be49e3d5b97cae0068fb4f3c..061301f1c4796837f0700da7a1dd85762910b0ba 100644 --- a/arch/arm/boot/dts/qcom/msm8996-sde-display.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-sde-display.dtsi @@ -94,8 +94,8 @@ label = "dsi_dual_sharp_video"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&sde_dsi0 &sde_dsi1>; - qcom,dsi-phy = <&sde_dsi_phy0 &sde_dsi_phy1>; + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; clocks = <&clock_mmss clk_ext_byte0_clk_src>, <&clock_mmss clk_ext_pclk0_clk_src>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -118,8 +118,8 @@ label = "single_dsi_sim"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&sde_dsi0>; - qcom,dsi-phy = <&sde_dsi_phy0>; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; clocks = <&clock_mmss clk_ext_byte0_clk_src>, <&clock_mmss clk_ext_pclk0_clk_src>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -140,8 +140,8 @@ label = "single_dsi_toshiba_720p"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&sde_dsi0>; - qcom,dsi-phy = <&sde_dsi_phy0>; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; clocks = <&clock_mmss clk_ext_byte0_clk_src>, <&clock_mmss clk_ext_pclk0_clk_src>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -161,8 +161,8 @@ label = "single_dsi_jdi_1080p"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&sde_dsi0>; - qcom,dsi-phy = <&sde_dsi_phy0>; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; clocks = <&clock_mmss clk_ext_byte0_clk_src>, <&clock_mmss clk_ext_pclk0_clk_src>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -180,8 +180,8 @@ label = "single_dsi_sharp_1080p"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&sde_dsi0>; - qcom,dsi-phy = <&sde_dsi_phy0>; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; clocks = <&clock_mmss clk_ext_byte0_clk_src>, <&clock_mmss clk_ext_pclk0_clk_src>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -209,8 +209,8 @@ qcom,display-type = "primary"; /* dsi1/dsi0 swapped due to IMGSWAP */ - qcom,dsi-ctrl = <&sde_dsi1 &sde_dsi0>; - qcom,dsi-phy = <&sde_dsi_phy0 &sde_dsi_phy1>; + qcom,dsi-ctrl = <&mdss_dsi1 &mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; clocks = <&clock_mmss clk_ext_byte0_clk_src>, <&clock_mmss clk_ext_pclk0_clk_src>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -231,8 +231,8 @@ label = "dsi_dual_nt35597_video"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&sde_dsi0 &sde_dsi1>; - qcom,dsi-phy = <&sde_dsi_phy0 &sde_dsi_phy1>; + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; clocks = <&clock_mmss clk_ext_byte0_clk_src>, <&clock_mmss clk_ext_pclk0_clk_src>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -253,8 +253,8 @@ label = "dsi_adv_7533_1"; qcom,display-type = "secondary"; - qcom,dsi-ctrl = <&sde_dsi0>; - qcom,dsi-phy = <&sde_dsi_phy0>; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; clocks = <&clock_mmss clk_ext_byte0_clk_src>, <&clock_mmss clk_ext_pclk0_clk_src>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -269,8 +269,8 @@ label = "dsi_adv_7533_2"; qcom,display-type = "tertiary"; - qcom,dsi-ctrl = <&sde_dsi1>; - qcom,dsi-phy = <&sde_dsi_phy1>; + qcom,dsi-ctrl = <&mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy1>; clocks = <&clock_mmss clk_ext_byte1_clk_src>, <&clock_mmss clk_ext_pclk1_clk_src>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -297,8 +297,8 @@ }; }; -&sde_kms { - connectors = <&sde_hdmi_tx &sde_hdmi &dsi_adv_7533_1 &dsi_adv_7533_2>; +&mdss_mdp { + connectors = <&mdss_hdmi &sde_hdmi &dsi_adv_7533_1 &dsi_adv_7533_2>; }; &dsi_dual_sharp_video { diff --git a/arch/arm/boot/dts/qcom/msm8996-sde.dtsi b/arch/arm/boot/dts/qcom/msm8996-sde.dtsi index b0688668e667aa76a7f90bb56b82a04b17c1e4ee..f0fa5dcb22240363df4a93ff0a3ad16fc99132c6 100644 --- a/arch/arm/boot/dts/qcom/msm8996-sde.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-sde.dtsi @@ -11,7 +11,7 @@ */ &soc { - sde_kms: qcom,sde_kms@900000 { + mdss_mdp: qcom,mdss_mdp@900000 { compatible = "qcom,sde-kms"; reg = <0x00900000 0x90000>, <0x009b0000 0x1040>, @@ -20,8 +20,6 @@ "vbif_phys", "vbif_nrt_phys"; - contiguous-region = <&cont_splash_mem &cont_splash_mem_hdmi>; - /* clock and supply entries */ clocks = <&clock_mmss clk_mdss_ahb_clk>, <&clock_mmss clk_mdss_axi_clk>, @@ -182,8 +180,8 @@ }; }; - smmu_kms_unsec: qcom,smmu_kms_unsec_cb { - compatible = "qcom,smmu_kms_unsec"; + smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb { + compatible = "qcom,smmu_mdp_unsec"; iommus = <&mdp_smmu 0>; }; @@ -213,7 +211,7 @@ }; }; - sde_dsi0: qcom,sde_dsi_ctrl0@994000 { + mdss_dsi0: qcom,mdss_dsi_ctrl0@994000 { compatible = "qcom,dsi-ctrl-hw-v1.4"; label = "dsi-ctrl-0"; cell-index = <0>; @@ -248,7 +246,7 @@ <22 512 0 0>, <22 512 0 1000>; - interrupt-parent = <&sde_kms>; + interrupt-parent = <&mdss_mdp>; interrupts = <4 0>; qcom,core-supply-entries { #address-cells = <1>; @@ -289,7 +287,7 @@ }; }; - sde_dsi1: qcom,sde_dsi_ctrl1@996000 { + mdss_dsi1: qcom,mdss_dsi_ctrl1@996000 { compatible = "qcom,dsi-ctrl-hw-v1.4"; label = "dsi-ctrl-1"; cell-index = <1>; @@ -323,7 +321,7 @@ <22 512 0 0>, <22 512 0 1000>; - interrupt-parent = <&sde_kms>; + interrupt-parent = <&mdss_mdp>; interrupts = <5 0>; qcom,core-supply-entries { #address-cells = <1>; @@ -363,7 +361,7 @@ }; }; - sde_dsi_phy0: qcom,sde_dsi_phy0@994400 { + mdss_dsi_phy0: qcom,mdss_dsi_phy0@994400 { compatible = "qcom,dsi-phy-v4.0"; label = "dsi-phy-0"; cell-index = <0>; @@ -422,7 +420,7 @@ }; }; - sde_dsi_phy1: qcom,sde_dsi_phy1@996400 { + mdss_dsi_phy1: qcom,mdss_dsi_phy1@996400 { compatible = "qcom,dsi-phy-v4.0"; label = "dsi-phy-1"; cell-index = <1>; @@ -481,7 +479,7 @@ }; }; - sde_hdmi_tx: qcom,hdmi_tx_8996@9a0000 { + mdss_hdmi: qcom,hdmi_tx@9a0000 { compatible = "qcom,hdmi-tx-8996"; reg = <0x009a0000 0x50c>, @@ -501,7 +499,7 @@ "core_clk", "alt_iface_clk", "extp_clk"; - interrupt-parent = <&sde_kms>; + interrupt-parent = <&mdss_mdp>; interrupts = <8 0>; hpd-gdsc-supply = <&gdsc_mdss>; qcom,hdmi-tx-hpd-gpio = <&pm8994_mpps 4 0>; @@ -513,8 +511,23 @@ &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>; - sde_hdmi_audio: qcom,sde-hdmi-audio-rx { + hdmi_audio: qcom,msm-hdmi-audio-rx { compatible = "qcom,msm-hdmi-audio-codec-rx"; }; }; }; + +/* dummy nodes for compatibility with 8996 mdss dtsi */ +&soc { + mdss_dsi: qcom,mdss_dsi_dummy { + /* dummy node for backward compatibility */ + }; + + mdss_hdmi_tx: qcom,mdss_hdmi_tx_dummy { + /* dummy node for backward compatibility */ + }; + + mdss_fb2: qcom,mdss_fb2_dummy { + /* dummy node for backward compatibility */ + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8996-v2.dtsi b/arch/arm/boot/dts/qcom/msm8996-v2.dtsi index 698c0193a1640d5945ee3c2e3d8fbdd8b04bfa15..9725bc3ee5303be7b833269b1640ecec863fc589 100644 --- a/arch/arm/boot/dts/qcom/msm8996-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-v2.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -480,7 +480,7 @@ gdsc-venus-supply = <&gdsc_venus>; }; -&sde_hdmi_tx { +&mdss_hdmi { hpd-gdsc-venus-supply = <&gdsc_venus>; }; diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index f5e059484c952c7273ea8b5b601637beb64f2249..80b3437beac6af766386b908ef20982d3720ad42 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -242,7 +242,6 @@ #include "msm8996-ion.dtsi" #include "msm8996-sde.dtsi" -#include "msm8996-mdss.dtsi" #include "msm8996-mdss-pll.dtsi" #include "msm8996-smp2p.dtsi" #include "msm8996-ipcrouter.dtsi" @@ -2335,17 +2334,15 @@ qcom,cnss { compatible = "qcom,cnss"; wlan-bootstrap-gpio = <&tlmm 46 0>; - vdd-wlan-en-supply = <&wlan_en_vreg>; + wlan-en-gpio = <&pm8994_gpios 8 0>; vdd-wlan-supply = <&rome_vreg>; vdd-wlan-io-supply = <&pm8994_s4>; vdd-wlan-xtal-supply = <&pm8994_l30>; vdd-wlan-core-supply = <&pm8994_s3>; wlan-ant-switch-supply = <&pm8994_l18_pin_ctrl>; - qcom,wlan-en-vreg-support; qcom,notify-modem-status; - pinctrl-names = "bootstrap_active", "bootstrap_sleep"; - pinctrl-0 = <&cnss_bootstrap_active>; - pinctrl-1 = <&cnss_bootstrap_sleep>; + pinctrl-names = "default"; + pinctrl-0 = <&cnss_default>; qcom,wlan-rc-num = <0>; qcom,wlan-ramdump-dynamic = <0x200000>; @@ -3357,82 +3354,6 @@ }; }; - qcom,msm-dai-tdm-pri-rx { - compatible = "qcom,msm-dai-tdm"; - qcom,msm-cpudai-tdm-group-id = <37120>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>; - qcom,msm-cpudai-tdm-clk-rate = <12288000>; - qcom,msm-cpudai-tdm-clk-internal = <1>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <1>; - qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; - dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36864>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; - - dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36866>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; - - dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36868>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; - - dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36870>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; - }; - - qcom,msm-dai-tdm-pri-tx { - compatible = "qcom,msm-dai-tdm"; - qcom,msm-cpudai-tdm-group-id = <37121>; - qcom,msm-cpudai-tdm-group-num-ports = <4>; - qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>; - qcom,msm-cpudai-tdm-clk-rate = <12288000>; - qcom,msm-cpudai-tdm-clk-internal = <1>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <1>; - qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; - dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36865>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; - - dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36867>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; - - dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36869>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; - - dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 { - compatible = "qcom,msm-dai-q6-tdm"; - qcom,msm-cpudai-tdm-dev-id = <36871>; - qcom,msm-cpudai-tdm-data-align = <0>; - }; - }; - qcom,msm-dai-tdm-sec-tx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37137>; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts index f5c33063643d475229962c06f2874357c1379ec2..48d5cb78611bb2ec27e7c5f9fc6f333cda234d3a 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts @@ -42,9 +42,6 @@ i2c@75b6000 { /* BLSP8 */ /* ADV7533 HDMI Bridge Chip removed on ADP Lite */ - adv7533@3d { - status = "disabled"; - }; adv7533@39 { status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts index d2aa5c854c83d295fbeac6bc73813565f2975791..7f6f3d5d4a4cbc15b1088d139df3f74b4bbf8e32 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 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 @@ -22,7 +22,7 @@ model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO ADP"; compatible = "qcom,msm8996-adp", "qcom,msm8996", "qcom,adp"; qcom,msm-id = <315 0x10000>; - qcom,board-id = <0x02010019 0>, <0x00010001 0>; + qcom,board-id = <0x02010019 0>; }; &spi_9 { diff --git a/arch/arm/boot/dts/qcom/msm8996pro.dtsi b/arch/arm/boot/dts/qcom/msm8996pro.dtsi index b9a2ccb973f2a2502468179b4714402e3c96dc61..252940c9c3e51d2da7f97f2dee062e15d05508c4 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996pro.dtsi @@ -22,7 +22,7 @@ qcom,msm-id = <305 0x10000>; chosen { - bootargs = "lpm_levels.sleep_disabled=1 fpsimd.fpsimd_settings=1 app_setting.use_app_setting=0 app_setting.use_32bit_app_setting_pro=1"; + bootargs = "fpsimd.fpsimd_settings=1 app_setting.use_app_setting=0 app_setting.use_32bit_app_setting_pro=1"; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996v3-auto.dtsi b/arch/arm/boot/dts/qcom/msm8996v3-auto.dtsi index 355062adf7ef09ead19db3937f6007d78695cbcf..32adb9a36dd4eef3722dbef30a62bd55733b39ad 100644 --- a/arch/arm/boot/dts/qcom/msm8996v3-auto.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996v3-auto.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016 - 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -167,40 +167,3 @@ < 560000000 7 >, < 624000000 7 >; }; - -&soc { - ipa_hw: qcom,ipa@680000 { - compatible = "qcom,ipa"; - reg = <0x680000 0x4effc>, - <0x684000 0x26934>; - reg-names = "ipa-base", "bam-base"; - interrupts = <0 333 0>, - <0 432 0>; - interrupt-names = "ipa-irq", "bam-irq"; - qcom,ipa-hw-ver = <5>; /* IPA core version = IPAv2.5 */ - qcom,ipa-hw-mode = <0>; - qcom,ee = <0>; - qcom,use-ipa-tethering-bridge; - qcom,ipa-bam-remote-mode; - qcom,modem-cfg-emb-pipe-flt; - clocks = <&clock_gcc clk_ipa_clk>; - clock-names = "core_clk"; - qcom,use-dma-zone; - qcom,msm-bus,name = "ipa"; - qcom,msm-bus,num-cases = <3>; - qcom,msm-bus,num-paths = <2>; - qcom,msm-bus,vectors-KBps = - <90 512 0 0>, <90 585 0 0>, /* No vote */ - <90 512 80000 640000>, <90 585 80000 640000>, /* SVS */ - <90 512 206000 960000>, <90 585 206000 960000>; /* PERF */ - qcom,bus-vector-names = "MIN", "SVS", "PERF"; - }; - - qcom,rmnet-ipa { - compatible = "qcom,rmnet-ipa"; - qcom,rmnet-ipa-ssr; - qcom,ipa-loaduC; - qcom,ipa-advertise-sg-support; - }; -}; - diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi index 86b68b2440a93e3af5f2b1cc8b6e1c746b6c594b..2095b4e0706985b35d33509a739acb0e1844721c 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi @@ -54,13 +54,6 @@ qcom,cam-vreg-op-mode = <0>; }; - laserled0: qcom,laserled@0 { - cell-index = <0>; - reg = <0x0>; - compatible = "qcom,laser-led"; - qcom,cci-master = <1>; - }; - actuator1: qcom,actuator@1 { cell-index = <1>; reg = <0x1>; @@ -329,7 +322,6 @@ qcom,eeprom-src = <&eeprom2>; qcom,led-flash-src = <&led_flash1>; qcom,actuator-src = <&actuator1>; - qcom,laserled-src = <&laserled0>; cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pm8998_l22>; cam_vdig-supply = <&pm8998_s3>; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi index 2af3bf2770960bf5b4b3d2193e5b7070e3f28890..14567c3b5010a018cb8b6f7c4c184baa098ff1e5 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 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 @@ -345,60 +345,6 @@ clock-names = "cam_src_clk", "cam_clk"; qcom,clock-rates = <24000000 0>; }; - - /* ToF Camera*/ - qcom,camera@3 { - cell-index = <3>; - compatible = "qcom,camera"; - reg = <0x3>; - qcom,csiphy-sd-index = <1>; - qcom,csid-sd-index = <3>; - qcom,mount-angle = <90>; - cam_vio-supply = <&pm8998_lvs1>; - qcom,cam-vreg-name = "cam_vio"; - qcom,cam-vreg-min-voltage = <1800000>; - qcom,cam-vreg-max-voltage = <1800000>; - qcom,cam-vreg-op-mode = <80000>; - qcom,gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk3_active - &cam_sensor_depth_v1_active - &cam_sensor_depth_v2_active - &cam_sensor_depth_default>; - pinctrl-1 = <&cam_sensor_mclk3_suspend - &cam_sensor_depth_v1_sleep - &cam_sensor_depth_v2_sleep - &cam_sensor_depth_sleep>; - gpios = <&tlmm 16 0>, - <&tlmm 24 0>, - <&tlmm 21 0>, - <&tlmm 28 0>, - <&tlmm 23 0>, - <&tlmm 7 0>; - qcom,gpio-vana = <1>; - qcom,gpio-custom2 = <2>; - qcom,gpio-reset = <3>; - qcom,gpio-custom3 = <4>; - qcom,gpio-custom1 = <5>; - qcom,gpio-req-tbl-num = <0 1 2 3 4 5>; - qcom,gpio-req-tbl-flags = <1 0 0 0 1 1>; - qcom,gpio-req-tbl-label = - "CAMIF_MCLK3", - "CAM_VANA", - "CAM_CUSTOM2", - "CAM_RESET1", - "CAM_CUSTOM3", - "CAM_CUSTOM1"; - qcom,sensor-position = <1>; /* 0 rear */ - qcom,sensor-mode = <0>; - qcom,cci-master = <1>; /* I2C 1 */ - status = "ok"; - clocks = <&clock_mmss clk_mclk3_clk_src>, - <&clock_mmss clk_mmss_camss_mclk3_clk>; - clock-names = "cam_src_clk", "cam_clk"; - qcom,clock-rates = <24000000 0>; - }; - }; &pm8998_gpios { diff --git a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi index 0859fd638a00a463cb31f8ec853089217d68f643..6ff62544b03c65459c6ed99b89cacbe0855f4c11 100644 --- a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi @@ -149,16 +149,6 @@ status = "okay"; }; - gpio@d200 { /* GPIO 19 - wil6210 refclk3_en */ - qcom,mode = <0>; /* Input */ - qcom,pull = <5>; /* No Pull */ - qcom,vin-sel = <1>; /* VIN1 GPIO_MV */ - qcom,src-sel = <0>; /* GPIO */ - qcom,invert = <0>; /* Invert */ - qcom,master-en = <1>; /* Enable GPIO */ - status = "okay"; - }; - /* GPIO 21 (NFC_CLK_REQ) */ gpio@d400 { qcom,mode = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi index 897ab12fe0a7f2e2f24878f01b375e612dc670e9..93b6a7664ed8feb9767bfdc25de76126b341d216 100644 --- a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi @@ -87,6 +87,7 @@ qcom,mdss-dsi-t-clk-post = <0x07>; qcom,mdss-dsi-t-clk-pre = <0x25>; qcom,mdss-dsi-tx-eot-append; + qcom,cmd-sync-wait-broadcast; qcom,esd-check-enabled; qcom,mdss-dsi-min-refresh-rate = <55>; qcom,mdss-dsi-max-refresh-rate = <60>; @@ -106,6 +107,7 @@ qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-tx-eot-append; + qcom,cmd-sync-wait-broadcast; qcom,esd-check-enabled; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; diff --git a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi index 3827b1bbf8ba067e23f24c938153ca00dd2886df..367d54f8a0bb2f83176b4203c7ece516f24f53a3 100644 --- a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi @@ -9,9 +9,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include -#include "msm8998-camera-sensor-mtp.dtsi" +/* #include "msm8998-camera-sensor-mtp.dtsi" */ &vendor { bluetooth: bt_wcn3990 { compatible = "qca,wcn3990"; @@ -150,16 +155,6 @@ status = "okay"; }; - gpio@d200 { /* GPIO 19 - wil6210 refclk3_en */ - qcom,mode = <0>; /* Input */ - qcom,pull = <5>; /* No Pull */ - qcom,vin-sel = <1>; /* VIN1 GPIO_MV */ - qcom,src-sel = <0>; /* GPIO */ - qcom,invert = <0>; /* Invert */ - qcom,master-en = <1>; /* Enable GPIO */ - status = "okay"; - }; - /* GPIO 21 (NFC_CLK_REQ) */ gpio@d400 { qcom,mode = <0>; @@ -240,6 +235,7 @@ }; }; +/* &mdss_hdmi_tx { pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active", "hdmi_active", "hdmi_sleep"; @@ -254,6 +250,7 @@ pinctrl-4 = <&mdss_hdmi_5v_suspend &mdss_hdmi_hpd_suspend &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>; }; +*/ &mdss_dp_ctrl { pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; @@ -597,6 +594,7 @@ }; }; +/* &vendor { mtp_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; @@ -609,3 +607,4 @@ &pmi8998_fg { qcom,battery-data = <&mtp_batterydata>; }; +*/ diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index 1abb28897fbd95458ecbd71fb651b0274dac3f11..71593012148d3a0e573a657994ec40fb880d7373 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -582,7 +582,7 @@ config { pins = "gpio37"; drive-strength = <2>; - bias-pull-up; + bias-pull-down; }; }; @@ -595,7 +595,7 @@ config { pins = "gpio37"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; }; }; @@ -993,86 +993,6 @@ }; }; - cam_sensor_depth_default: cam_sensor_depth_default { - mux { - pins = "gpio28","gpio23","gpio7"; - function = "gpio"; - }; - - config { - pins = "gpio28","gpio23","gpio7"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_depth_sleep: cam_sensor_depth_sleep { - mux { - pins = "gpio28","gpio23","gpio7"; - function = "gpio"; - }; - - config { - pins = "gpio28","gpio23","gpio7"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_depth_v1_active: cam_sensor_depth_v1_active { - /* Depth VANA */ - mux { - pins = "gpio24"; - function = "gpio"; - }; - - config { - pins = "gpio24"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_depth_v1_sleep: cam_sensor_depth_v1_sleep { - mux { - pins = "gpio24"; - function = "gpio"; - }; - - config { - pins = "gpio24"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_depth_v2_active: cam_sensor_depth_v2_active { - /* Depth CUSTOM2 */ - mux { - pins = "gpio21"; - function = "gpio"; - }; - - config { - pins = "gpio21"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_depth_v2_sleep: cam_sensor_depth_v2_sleep { - mux { - pins = "gpio21"; - function = "gpio"; - }; - - config { - pins = "gpio21"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - cam_sensor_mclk0_active: cam_sensor_mclk0_active { /* MCLK0 */ mux { diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi index c4a428635231297425ef896623fa9e98b4da111e..97c4c5b1d4553fbd5c1c65f1f46818721f38f7ce 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi @@ -143,16 +143,6 @@ qcom,out-strength = <1>; }; - gpio@d200 { /* GPIO 19 - wil6210 refclk3_en */ - qcom,mode = <0>; /* Input */ - qcom,pull = <5>; /* No Pull */ - qcom,vin-sel = <1>; /* VIN1 GPIO_MV */ - qcom,src-sel = <0>; /* GPIO */ - qcom,invert = <0>; /* Invert */ - qcom,master-en = <1>; /* Enable GPIO */ - status = "okay"; - }; - /* GPIO 21 (NFC_CLK_REQ) */ gpio@d400 { qcom,mode = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi index 3c6b23d9581c7b2470b1974a272816f2427bf967..a3eb3e5ab0d0a265080ea92b0a9af74ac8e005d2 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi @@ -139,16 +139,6 @@ status = "okay"; }; - gpio@d200 { /* GPIO 19 - wil6210 refclk3_en */ - qcom,mode = <0>; /* Input */ - qcom,pull = <5>; /* No Pull */ - qcom,vin-sel = <1>; /* VIN1 GPIO_MV */ - qcom,src-sel = <0>; /* GPIO */ - qcom,invert = <0>; /* Invert */ - qcom,master-en = <1>; /* Enable GPIO */ - status = "okay"; - }; - /* GPIO 21 (NFC_CLK_REQ) */ gpio@d400 { qcom,mode = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-yoshino-lilac_generic.dts b/arch/arm/boot/dts/qcom/msm8998-v2-yoshino-lilac_generic.dts new file mode 100644 index 0000000000000000000000000000000000000000..f03cb1a2cc77967d3f971f6894d10bdae9b38b74 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2-yoshino-lilac_generic.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +/dts-v1/; + +#include "msm8998-v2.dtsi" +#include "msm8998-mdss-panels.dtsi" +#include "msm8998-mtp.dtsi" +#include "msm8998-yoshino-lilac_generic.dtsi" + +/ { + model = "SoMC Lilac-ROW(MSM8998 v2)"; + compatible = "somc,lilac-row", "qcom,msm8998"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-yoshino-poplar_dsds.dts b/arch/arm/boot/dts/qcom/msm8998-v2-yoshino-poplar_dsds.dts new file mode 100644 index 0000000000000000000000000000000000000000..286ac88b42d9fb673a4f437ca65c740eda841084 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2-yoshino-poplar_dsds.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +/dts-v1/; + +#include "msm8998-v2.dtsi" +#include "msm8998-mdss-panels.dtsi" +#include "msm8998-mtp.dtsi" +#include "msm8998-yoshino-poplar_dsds.dtsi" + +/ { + model = "SoMC Poplar-DSDS(MSM8998 v2)"; + compatible = "somc,poplar-dsds", "qcom,msm8998"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-yoshino-poplar_generic.dts b/arch/arm/boot/dts/qcom/msm8998-v2-yoshino-poplar_generic.dts new file mode 100644 index 0000000000000000000000000000000000000000..26f8e1d13b74c54db88d8d5a4da293cc1a3b93ee --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2-yoshino-poplar_generic.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +/dts-v1/; + +#include "msm8998-v2.dtsi" +#include "msm8998-mdss-panels.dtsi" +#include "msm8998-mtp.dtsi" +#include "msm8998-yoshino-poplar_generic.dtsi" + +/ { + model = "SoMC Poplar-ROW(MSM8998 v2)"; + compatible = "somc,poplar-row", "qcom,msm8998"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-yoshino-lilac_generic.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-yoshino-lilac_generic.dts new file mode 100644 index 0000000000000000000000000000000000000000..c4ea8ae8ea94f52e75eea5be1d117b7c15acd4b2 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-yoshino-lilac_generic.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +/dts-v1/; + +#include "msm8998-v2.1.dtsi" +#include "msm8998-mdss-panels.dtsi" +#include "msm8998-mtp.dtsi" +#include "msm8998-yoshino-lilac_generic.dtsi" + +/ { + model = "SoMC Lilac-ROW(MSM8998 v2.1)"; + compatible = "somc,lilac-row", "qcom,msm8998"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-yoshino-poplar_dsds.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-yoshino-poplar_dsds.dts new file mode 100644 index 0000000000000000000000000000000000000000..98a5f0b7e1812e44a425d0f5443e3f775b896a03 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-yoshino-poplar_dsds.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +/dts-v1/; + +#include "msm8998-v2.1.dtsi" +#include "msm8998-mdss-panels.dtsi" +#include "msm8998-mtp.dtsi" +#include "msm8998-yoshino-poplar_dsds.dtsi" + +/ { + model = "SoMC Poplar-DSDS(MSM8998 v2.1)"; + compatible = "somc,poplar-dsds", "qcom,msm8998"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-yoshino-poplar_generic.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-yoshino-poplar_generic.dts new file mode 100644 index 0000000000000000000000000000000000000000..3ddda1dbf0bfc6ae800698ea55c4c1a9fae9e543 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-yoshino-poplar_generic.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +/dts-v1/; + +#include "msm8998-v2.1.dtsi" +#include "msm8998-mdss-panels.dtsi" +#include "msm8998-mtp.dtsi" +#include "msm8998-yoshino-poplar_generic.dtsi" + +/ { + model = "SoMC Poplar-ROW(MSM8998 v2.1)"; + compatible = "somc,poplar-row", "qcom,msm8998"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi index acdd4bdcd95b8b5130330e7e3ba9647488cdbae4..b2f30de94bbc9e1251c7cebe9ce5da7a98e4b6c5 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi @@ -436,7 +436,7 @@ 0x9ac 0x00 0x00 0x8a0 0x01 0x00 0x9e0 0x00 0x00 - 0x9dc 0x20 0x00 + 0x9dc 0x01 0x00 0x9a8 0x00 0x00 0x8a4 0x01 0x00 0x8a8 0x73 0x00 diff --git a/arch/arm/boot/dts/qcom/msm8998-yoshino-common.dtsi b/arch/arm/boot/dts/qcom/msm8998-yoshino-common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..44040fd14c9b1e31e536eb75f7e8679c6cb7075e --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-yoshino-common.dtsi @@ -0,0 +1,3721 @@ +/* arch/arm64/boot/dts/qcom/msm8998-yoshino-common.dtsi + * + * 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. + */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ + + +/ { + aliases { + i2c8 = &i2c_8; + }; + + reserved-memory { + debug_region: debug_region@ffb00000 { + compatible = "removed-dma-pool", "qcom,debug_memory"; + no-map; + reg = <0 0xffb00000 0 0x100000>; + label = "debug_mem"; + }; + + pstore_reserve_mem: pstore_reserve_mem_region_region@ffc00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0xffc00000 0 0x00100000>; + }; + }; +}; + +&firmware { + android { + fstab { + vendor { + fsmgr_flags = "wait,verify=/dev/block/platform/soc/1da4000.ufshc/by-name/fsmetadata"; + }; + + system { + compatible = "android,system"; + dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/system"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,verify=/dev/block/platform/soc/1da4000.ufshc/by-name/fsmetadata"; + status = "ok"; + }; + }; + }; +}; + +&soc { + pinctrl@03400000 { + disabled-pins = <0 1 2 3 81 82 83 84>; + }; + + fpc1145 { + status = "ok"; + compatible = "fpc,fpc1020", "fpc1145"; + interrupt-parent = <&tlmm>; + interrupts = <121 0x0>; + fpc,gpio_rst = <&tlmm 40 0x0>; + fpc,gpio_irq = <&tlmm 121 0x0>; + vdd_ana-supply = <&pm8998_l6>; + + pinctrl-names = "fpc1145_reset_reset", + "fpc1145_reset_active", + "fpc1145_irq_active"; + + pinctrl-0 = <&msm_gpio_40>; + pinctrl-1 = <&msm_gpio_40_output_high>; + pinctrl-2 = <&msm_gpio_121>; + }; + + somc_pinctrl: somc_pinctrl { + compatible = "somc-pinctrl"; + pinctrl-names = "platform_common_default", + "product_common_default", + "variant_default"; + pinctrl-0 = <&msm_gpio_4 + &msm_gpio_5 &msm_gpio_6 &msm_gpio_7 &msm_gpio_8 &msm_gpio_9 + &msm_gpio_10 &msm_gpio_11_suspend &msm_gpio_12 &msm_gpio_13 &msm_gpio_14 + &msm_gpio_15 &msm_gpio_16 &msm_gpio_17 &msm_gpio_18 &msm_gpio_19 + &msm_gpio_20 &msm_gpio_21 &msm_gpio_22_suspend &msm_gpio_23 &msm_gpio_24 + &msm_gpio_25 &msm_gpio_26 &msm_gpio_27 &msm_gpio_28 &msm_gpio_29 + &msm_gpio_30 &msm_gpio_31 &msm_gpio_32 &msm_gpio_33 &msm_gpio_34 + &msm_gpio_35 &msm_gpio_36 &msm_gpio_37 &msm_gpio_39 &msm_gpio_40 + &msm_gpio_41 &msm_gpio_42 &msm_gpio_43 &msm_gpio_44 &msm_gpio_49 + &msm_gpio_50 &msm_gpio_51 &msm_gpio_52 &msm_gpio_55 &msm_gpio_56 + &msm_gpio_57 &msm_gpio_58 &msm_gpio_59 &msm_gpio_60 &msm_gpio_61 + &msm_gpio_62 &msm_gpio_63 &msm_gpio_65 &msm_gpio_66 &msm_gpio_67 + &msm_gpio_68 &msm_gpio_69 &msm_gpio_75 &msm_gpio_76 &msm_gpio_77 + &msm_gpio_78 &msm_gpio_79 &msm_gpio_80 &msm_gpio_81 &msm_gpio_82 + &msm_gpio_83 &msm_gpio_84 &msm_gpio_85 &msm_gpio_86 &msm_gpio_87 + &msm_gpio_88 &msm_gpio_90 &msm_gpio_91 &msm_gpio_92 + &msm_gpio_93 &msm_gpio_94 &msm_gpio_95 &msm_gpio_96 &msm_gpio_99 + &msm_gpio_100 &msm_gpio_104 &msm_gpio_108 &msm_gpio_112 &msm_gpio_114 + &msm_gpio_116 &msm_gpio_120 &msm_gpio_121 &msm_gpio_122 &msm_gpio_123 + &msm_gpio_124 &msm_gpio_125 &msm_gpio_126 &msm_gpio_128 &msm_gpio_129 + &msm_gpio_133>; + + /* If product common default setting is needed, + fill pinctrl-1 value in _common.dtsi */ + pinctrl-1 = <>; + + /* If variant specific default setting is needed, + fill pinctrl-2 value in .dtsi */ + pinctrl-2 = <>; + + /* If variant specific default setting is needed, + fill pinctrl-3 value in .dtsi */ + pinctrl-3 = <>; + }; + + /* SPI: BLSP1 */ + spi@c175000 { /* BLSP1 QUP1 */ + qcom,clk-freq-out = <4800000>; + status = "disabled"; + }; + + /* UART: BLSP3 */ + uart@c171000 { /* BLSP1 UART3 */ + qcom,clk-freq-out = <4000000>; + status = "okay"; + }; + + /* I2C: BLSP5 */ + i2c@c179000 { /* BLSP1 QUP5 */ + pinctrl-0 = <&msm_gpio_87 &msm_gpio_88>; + pinctrl-1 = <&msm_gpio_87 &msm_gpio_88>; + qcom,clk-freq-out = <355000>; + status = "okay"; + + /delete-node/ synaptics@20; + +#include "clearpad-ic-default-regoffset.dtsi" + + synaptics_clearpad@2c { + compatible = "synaptics,clearpad"; + reg = <0x2c>; + interrupt-parent = <&tlmm>; + interrupts = <125 0x2>; + synaptics,irq_gpio = <&tlmm 125 0x00>; + post_probe_start = <0>; + synaptics,firmware_name = "touch_module_id_0x%02x.img"; + flash_on_post_probe = <1>; + flip_config = <0>; + watchdog_enabled = <1>; + watchdog_delay_ms = <3000>; + charger_supported = <0>; + pen_supported = <0>; + glove_supported = <1>; + cover_supported = <1>; + touch_pressure_enabled = <1>; + touch_size_enabled = <0>; + touch_orientation_enabled = <0>; + preset_x_max = <2159>; + preset_y_max = <3839>; + preset_n_fingers = <10>; + wakeup_gesture { + double_tap { + gesture_code = <0x0003>; + event_00 { + type = <2>; /* LOG */ + message = "=== DOUBLE TAP ==="; + }; + event_01 { + type = <1>; /* KEY */ + code = <531>; /* TOUCHPAD_ON */ + down = <1>; + }; + event_02 { + type = <1>; /* KEY */ + code = <531>; /* TOUCHPAD_ON */ + down = <0>; + }; + event_03 { + type = <99>; /* END */ + }; + }; + }; + /* chip settings */ + clearpad_default { + flash_default_timeout_ms = <20000>; + calibrate_on_fwflash = <0>; + calibration_supported = <0>; + hwreset_delay_for_powerup_ms = <220>; + interrupt_default_wait_ms = <1000>; + charger_only_delay_ms = <200>; + }; + S3330 { + flash_default_timeout_ms = <20000>; + calibrate_on_fwflash = <0>; + calibration_supported = <0>; + hwreset_delay_for_powerup_ms = <220>; + interrupt_default_wait_ms = <1000>; + charger_only_delay_ms = <200>; + }; + S332U { + flash_default_timeout_ms = <20000>; + calibrate_on_fwflash = <1>; + calibration_supported = <1>; + hwreset_delay_for_powerup_ms = <220>; + interrupt_default_wait_ms = <1000>; + charger_only_delay_ms = <200>; + }; + S3500 { + flash_default_timeout_ms = <20000>; + calibrate_on_fwflash = <0>; + calibration_supported = <0>; + hwreset_delay_for_powerup_ms = <220>; + interrupt_default_wait_ms = <1000>; + charger_only_delay_ms = <16>; + }; + }; + }; + + /* I2C: BLSP7 */ + i2c@c1b5000 { /* BLSP2 QUP1 */ + pinctrl-0 = <&msm_gpio_55 &msm_gpio_56>; + pinctrl-1 = <&msm_gpio_55 &msm_gpio_56>; + qcom,clk-freq-out = <355000>; + status = "okay"; + }; + + /* UART: BLSP8 */ + serial@0c1b0000 { /* BLSP2 UART2 */ + pinctrl-names = "uart_active"; + pinctrl-0 = <&msm_gpio_4 &msm_gpio_5>; + status = "okay"; + }; + + /* I2C : BLSP8 */ + i2c_8: i2c@c1b6000 { /* BLSP2 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0xC1B6000 0x600>; + interrupt-names = "qup_irq"; + interrupts = <0 102 0>; + dmas = <&dma_blsp2 8 64 0x20000020 0x20>, + <&dma_blsp2 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <355000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>, + <&clock_gcc clk_gcc_blsp2_qup2_i2c_apps_clk>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&msm_gpio_6 &msm_gpio_7>; + pinctrl-1 = <&msm_gpio_6_suspend &msm_gpio_7_suspend>; + status = "okay"; + tcs3490@72 { + compatible = "ams,tcs3490"; + reg = <0x72>; + interrupt-parent = <&tlmm>; + interrupts = <11 0x0>; + ams,rgbcir-supply_name = "rgbcir_vdd"; + rgbcir-gpio-vdd-supply = <&cam_vio_verg>; + pinctrl-names = "rgbcir_irq_active", "rgbcir_irq_suspend"; + pinctrl-0 = <&msm_gpio_11>; + pinctrl-1 = <&msm_gpio_11_suspend>; + ams,rgbcir-vdd-supply = <0>; + ams,rgbcir-gpio-vdd = <1>; + ams,rgbcir-vio-supply = <0>; + }; + tof_sensor@52 { + compatible = "tof_sensor"; + reg = <0x52>; + interrupt-parent = <&tlmm>; + interrupts = <22 0x0>; + tof-supply_name = "tof_avdd"; + tof-gpio-avdd-supply = <&cam_vio_verg>; + pinctrl-names = "tof_irq_active", "tof_irq_suspend"; + pinctrl-0 = <&msm_gpio_22 &msm_gpio_27>; + pinctrl-1 = <&msm_gpio_22_suspend &msm_gpio_27>; + tof-reset-gpio = <&tlmm 27 0>; + sony,tof-sensor-name = "VL53L0"; + sony,tof-need-cam-on = <1>; + sony,tof-sensor-facing = <0>; + sony,tof-avdd-supply = <0>; + sony,tof-gpio-avdd = <1>; + }; + }; + + bu520x1nvx { + compatible = "rohm,bu520x1nvx"; + + acc_cover { + label = "lid"; + gpios = <&tlmm 124 0x1>; + lid-pin = <1>; + open-debounce-interval = <120>; + close-debounce-interval = <300>; + }; + }; + + mdss_dsi: qcom,mdss_dsi@0 { + mdss_dsi0: qcom,mdss_dsi_ctrl0@c994000 { + vddio-supply = <&pm8998_l14>; + touch-avdd-supply = <&pm8998_l28>; + }; + + mdss_dsi1: qcom,mdss_dsi_ctrl1@c996000 { + vddio-supply = <&pm8998_l14>; + touch-avdd-supply = <&pm8998_l28>; + }; + qcom,core-supply-entries { + qcom,core-supply-entry@0 { + /delete-property/ qcom,supply-lp-mode-disable-allowed; + }; + }; + qcom,phy-supply-entries { + qcom,phy-supply-entry@0 { + /delete-property/ qcom,supply-lp-mode-disable-allowed; + }; + }; + }; + + dsi_panel_pwr_supply_hybrid_incell: dsi_panel_pwr_supply_hybrid_incell { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <2>; + qcom,supply-name = "touch-avdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + + dsi_panel_pwr_supply_full_incell: dsi_panel_pwr_supply_full_incell { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + /delete-node/ qcom,panel-supply-entry@3; + }; + + qcom,cci@ca0c000 { + qcom,i2c_fast_mode { + qcom,hw-thigh = <43>; + qcom,hw-tlow = <64>; + qcom,hw-tsu-sto = <41>; + qcom,hw-tsu-sta = <41>; + qcom,hw-thd-dat = <25>; + qcom,hw-thd-sta = <35>; + qcom,hw-tbuf = <64>; + qcom,hw-scl-stretch-en = <0>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <3>; + qcom,cci-clk-src = <37500000>; + status = "ok"; + }; + + qcom,i2c_fast_plus_mode { + qcom,hw-thigh = <16>; + qcom,hw-tlow = <22>; + qcom,hw-tsu-sto = <17>; + qcom,hw-tsu-sta = <18>; + qcom,hw-thd-dat = <16>; + qcom,hw-thd-sta = <15>; + qcom,hw-tbuf = <19>; + qcom,hw-scl-stretch-en = <1>; + qcom,hw-trdhld = <3>; + qcom,hw-tsp = <3>; + qcom,cci-clk-src = <37500000>; + status = "ok"; + }; + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,sony_camera_0"; + reg = <0x0>; + interrupt-parent = <&tlmm>; + interrupts = <96 0x0>; + status = "ok"; + qcom,slave-id = <0x20 0x0 0x0000>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <0>; + qcom,sensor-name = "sony_camera_0"; + cam_vaf-supply = <&pm8998_l19>; + cam_vio_gpio-supply = <&cam_vio_verg>; + cam_vdig_gpio-supply = <&cam_vdig_rear_verg>; + qcom,cam-vreg-name = "cam_vaf", "cam_vio_gpio", "cam_vdig_gpio"; + qcom,cam-vreg-type = <0 0 0>; + qcom,cam-vreg-min-voltage = <2700000 0 0>; + qcom,cam-vreg-max-voltage = <2700000 0 0>; + qcom,cam-vreg-op-mode = <300000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active &msm_gpio_30>; + pinctrl-1 = <&cam_sensor_mclk0_suspend &msm_gpio_30>; + gpios = <&tlmm 13 0>, <&tlmm 30 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0"; + qcom,csi-lane-assign = <0x4320>; + qcom,csi-lane-mask = <0x1F>; + qcom,sensor-position = <0>; + qcom,sensor-mode = <1>; + qcom,cci-master = <0>; + clocks = <&clock_mmss clk_mclk0_clk_src>, <&clock_mmss clk_mmss_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + sony,i2c_addr = <0x20>; + sony,eeprom_addr = <0xA2>; + sony,eeprom_type = <2>; + sony,eeprom_max_len = <2048>; + sony,gpio_af = <0>; + sony,subdev_code = <0x3007>; + sony_camera_module_0: sony,camera_modules { + status = "disabled"; + }; + }; + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,sony_camera_1"; + reg = <0x1>; + interrupt-parent = <&tlmm>; + status = "ok"; + qcom,slave-id = <0x6c 0x0 0x0000>; + qcom,csiphy-sd-index = <2>; + qcom,csid-sd-index = <2>; + qcom,mount-angle = <270>; + qcom,sensor-name = "sony_camera_1"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vdig-supply = <&pm8998_s3>; + cam_vaf-supply = <&pm8998_l22>; + cam_vio_gpio-supply = <&cam_vio_verg>; + cam_vdig_gpio-supply = <&cam_vdig_front_verg>; + qcom,cam-vreg-name = "cam_vio", "cam_vaf", "cam_vdig", "cam_vio_gpio", "cam_vdig_gpio"; + qcom,cam-vreg-type = <1 0 0 0 0>; + qcom,cam-vreg-min-voltage = <0 2700000 1352000 0 0>; + qcom,cam-vreg-max-voltage = <0 2700000 1352000 0 0>; + qcom,cam-vreg-op-mode = <0 150000 105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active &msm_gpio_28>; + pinctrl-1 = <&cam_sensor_mclk1_suspend &msm_gpio_28>; + gpios = <&tlmm 14 0>, <&tlmm 28 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", "CAM_RESET2"; + qcom,csi-lane-assign = <0x4320>;/* NONE */ + qcom,csi-lane-mask = <0x1F>; /* NONE */ + qcom,sensor-position = <1>; + qcom,sensor-mode = <1>; + qcom,cci-master = <1>; + clocks = <&clock_mmss clk_mclk1_clk_src>, <&clock_mmss clk_mmss_camss_mclk1_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + sony,i2c_addr = <0x34>; + sony,eeprom_addr = <0xA0>; + sony,eeprom_type = <0>; + sony,eeprom_max_len = <2048>; + sony,gpio_af = <0>; + sony,subdev_code = <0x3007>; + sony_camera_module_1: sony,camera_modules { + status = "disabled"; + }; + }; + }; + + ldo_vibrator { + compatible = "ldo-vibrator"; + gpios = <&pmi8998_gpios 5 1>; + }; + + qcom,sensor-information { + /* msm_therm */ + sensor_information23: qcom,sensor-information-23 { + qcom,scaling-factor = <10>; + }; + + /* quiet_therm */ + sensor_information27: qcom,sensor-information-27 { + qcom,scaling-factor = <10>; + qcom,alias-name = "bl_therm"; + }; + + /* ufs_therm */ + sensor_information100: qcom,sensor-information-100 { + qcom,sensor-type = "adc"; + qcom,scaling-factor = <10>; + qcom,sensor-name = "ufs_therm"; + }; + + /* flash_therm */ + sensor_information101: qcom,sensor-information-101 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "flash_therm"; + qcom,scaling-factor = <10>; + }; + + /* xo_therm */ + sensor_information102: qcom,sensor-information-102 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "xo_therm"; + }; + + /* pa_therm2 */ + sensor_information103: qcom,sensor-information-103 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "pa_therm2"; + }; + /* bms */ + sensor_information104: qcom,sensor-information-104 { + qcom,sensor-type = "adc"; + qcom,sensor-name = "bms"; + qcom,alias-name = "batt_therm"; + qcom,scaling-factor = <1000>; + }; + }; + + sound-9335 { + qcom,msm-mbhc-hphl-swh = <1>; + /delete-property/ qcom,hph-en1-gpio; + /delete-property/ qcom,hph-en0-gpio; + /delete-property/ qcom,us-euro-gpios; + qcom,ear-en-gpios = <&pm8005_gpios 1 0>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "ANCLeft Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC3", "MIC BIAS4", + "MIC BIAS4", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + }; + + qcom,wdt@17817000 { + qcom,bark-time = <12000>; + }; + + sim_detect { + compatible = "sim-detect"; + + sim1_det { + label = "sim-detection"; + gpios = <&tlmm 112 0x0>; + debounce-interval = <10>; + }; + }; + + ramoops { + compatible = "ramoops"; + memory-region = <&pstore_reserve_mem>; + record-size = <0x0 0x1000>; + console-size = <0x0 0x40000>; + ftrace-size = <0x0 0x0>; + pmsg-size = <0x0 0x0>; + ecc-size = <0x0 0x0>; + }; + + gpio_keys { + vol_dn { + label = "volume_down"; + gpios = <&pm8998_gpios 5 0x1>; + linux,input-type = <1>; + linux,code = <114>; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; + + cam_vio_verg: cam_vio_verg { + compatible = "regulator-fixed"; + regulator-name = "cam_vio_verg"; + startup-delay-us = <0>; + enable-active-high; + gpio = <&pmi8998_gpios 1 0>; + }; + + cam_vdig_front_verg: cam_vdig_front_verg { + compatible = "regulator-fixed"; + regulator-name = "cam_vdig_front_verg"; + startup-delay-us = <0>; + enable-active-high; + gpio = <&tlmm 25 0>; + }; + + cam_vdig_rear_verg: cam_vdig_rear_verg { + compatible = "regulator-fixed"; + regulator-name = "cam_vdig_rear_verg"; + startup-delay-us = <0>; + enable-active-high; + gpio = <&tlmm 21 0>; + }; + + qcom,bcl { + qcom,ibat-monitor { + qcom,soc-low-threshold = <5>; + }; + }; +}; + +&sony_camera_module_0 { + module_names = "GENERIC", "SOI20BS2"; + default_module_name = "SOI20BS2"; + + GENERIC { + mount_angle = <90>; + sensor_rotation = <0>; + sensor_facing = <0x00>; + sensor_config_delay_num = <12>; + sensor_config_delay = <4 3 4 4 4 4 4 4 4 4 4 4>; + temperature_check_skip_num = <0>; + total_pixel_number_w = <5520>; + total_pixel_number_h = <4032>; + active_pixel_number_x = <8>; + active_pixel_number_y = <176>; + active_pixel_number_w = <5504>; + active_pixel_number_h = <3808>; + min_focus_distance = <120>; + hyper_focal_distance = <4321>; + diagonal_len = "7.73"; + unit_cell_size_w = "1.22"; + unit_cell_size_h = "1.22"; + min_f_number = "2.00"; + max_f_number = "2.00"; + min_focus_pos = <1>; + max_focus_pos = <1024>; + min_focus_dac = <0x0000>; + max_focus_dac = <0x03FF>; + focus_inf_range_offset = <0x19>; + focus_macro_range_offset = <0x38>; + focus_lens_stroke_inf_to_1m = <0x14>; + focus_lens_stroke_1m_to_macro = <0x95>; + focus_lens_stroke_inf_to_macro = <0xA9>; + focus_calc_type = <0x01>; + focus_wob_time = <0x35>; + has_3a = <0>; + has_focus_actuator = <1>; + need_standby_af = <0>; + i2c_freq_mode = <3>; + has_pdaf = <1>; + has_rs = <1>; + has_multi_output = <0>; + has_super_slow = <1>; + has_sub_sensor = <0>; + has_aube = <0>; + has_flicker_detector = <1>; + has_hdr = <1>; + has_seamless_mode_change = <1>; + has_gph = <1>; + pdaf_free_area_num = <8>; + pdaf_fixed_area_size_w = <16>; + pdaf_fixed_area_size_h = <12>; + pll_num = <26>; + pll = <290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290>; + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VAF", + "CAM_VDIG_GPIO", + "CAM_VIO_GPIO", + "EXIT"; + GPIO_RESET = <5 0x0 0 5>; + CAM_CLK = <10 0xFFFFFFFF 0 0>; + CAM_VAF = <3 0xFFFFFFFF 0 0>; + CAM_VDIG_GPIO = <6 0xFFFFFFFF 0 5>; + CAM_VIO_GPIO = <7 0xFFFFFFFF 0 30>; + EXIT = <12 0x0 0 0>; + }; + power_on { + commands = + "CAM_VDIG_GPIO", + "CAM_VIO_GPIO", + "CAM_VAF", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + CAM_VDIG_GPIO = <6 0 0 1>; + CAM_VIO_GPIO = <7 0 0 1>; + CAM_VAF = <3 2700 106500 3>; + CAM_CLK = <10 0 0 1>; + GPIO_RESET = <5 1 0 1>; + EXIT = <12 0x0 0 0>; + }; + }; + SOI20BS2 { + mount_angle = <90>; + sensor_rotation = <0>; + sensor_facing = <0x00>; + sensor_config_delay_num = <12>; + sensor_config_delay = <4 3 4 4 4 4 4 4 4 4 4 4>; + temperature_check_skip_num = <0>; + total_pixel_number_w = <5520>; + total_pixel_number_h = <4032>; + active_pixel_number_x = <8>; + active_pixel_number_y = <176>; + active_pixel_number_w = <5504>; + active_pixel_number_h = <3808>; + min_focus_distance = <120>; + hyper_focal_distance = <4321>; + diagonal_len = "7.73"; + unit_cell_size_w = "1.22"; + unit_cell_size_h = "1.22"; + min_f_number = "2.00"; + max_f_number = "2.00"; + min_focus_pos = <1>; + max_focus_pos = <1024>; + min_focus_dac = <0x0000>; + max_focus_dac = <0x03FF>; + focus_inf_range_offset = <0x24>; + focus_macro_range_offset = <0x38>; + focus_lens_stroke_inf_to_1m = <0x14>; + focus_lens_stroke_1m_to_macro = <0x95>; + focus_lens_stroke_inf_to_macro = <0xA9>; + focus_calc_type = <0x01>; + focus_wob_time = <0x35>; + has_3a = <0>; + has_focus_actuator = <1>; + need_standby_af = <0>; + i2c_freq_mode = <3>; + has_pdaf = <1>; + has_rs = <1>; + has_multi_output = <0>; + has_super_slow = <1>; + has_sub_sensor = <0>; + has_aube = <0>; + has_flicker_detector = <1>; + has_hdr = <1>; + has_seamless_mode_change = <1>; + has_gph = <1>; + pdaf_free_area_num = <8>; + pdaf_fixed_area_size_w = <16>; + pdaf_fixed_area_size_h = <12>; + pll_num = <26>; + pll = <290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290 290>; + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VAF", + "CAM_VDIG_GPIO", + "CAM_VIO_GPIO", + "EXIT"; + GPIO_RESET = <5 0x0 0 5>; + CAM_CLK = <10 0xFFFFFFFF 0 0>; + CAM_VAF = <3 0xFFFFFFFF 0 0>; + CAM_VDIG_GPIO = <6 0xFFFFFFFF 0 5>; + CAM_VIO_GPIO = <7 0xFFFFFFFF 0 1>; + EXIT = <12 0x0 0 0>; + }; + power_on { + commands = + "CAM_VDIG_GPIO", + "CAM_VIO_GPIO", + "CAM_VAF", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + CAM_VDIG_GPIO = <6 0 0 1>; + CAM_VIO_GPIO = <7 0 0 1>; + CAM_VAF = <3 2700 106500 3>; + CAM_CLK = <10 0 0 1>; + GPIO_RESET = <5 1 0 1>; + EXIT = <12 0x0 0 0>; + }; + }; +}; + +&sony_camera_module_1 { + module_names = "GENERIC", "SOI13BS1", "SEM13BS1"; + default_module_name = "SOI13BS1"; + + GENERIC { + mount_angle = <270>; + sensor_rotation = <180>; + sensor_facing = <1>; + sensor_config_delay_num = <12>; + sensor_config_delay = <3 3 3 3 3 3 3 3 3 3 3 3>; + temperature_check_skip_num = <8>; + total_pixel_number_w = <4224>; + total_pixel_number_h = <3192>; + active_pixel_number_x = <8>; + active_pixel_number_y = <56>; + active_pixel_number_w = <4208>; + active_pixel_number_h = <3120>; + min_focus_distance = <100>; + hyper_focal_distance = <2000>; + diagonal_len = "5.867"; + unit_cell_size_w = "1.12"; + unit_cell_size_h = "1.12"; + min_f_number = "2.00"; + max_f_number = "2.00"; + min_focus_pos = <1>; + max_focus_pos = <1024>; + min_focus_dac = <0x0000>; + max_focus_dac = <0x03FF>; + focus_inf_range_offset = <0x24>; + focus_macro_range_offset = <0x24>; + focus_lens_stroke_inf_to_1m = <0x09>; + focus_lens_stroke_1m_to_macro = <0x55>; + focus_lens_stroke_inf_to_macro = <0x5E>; + focus_calc_type = <0x01>; + focus_wob_time = <0>; + has_3a = <0>; + has_focus_actuator = <1>; + need_standby_af = <0>; + i2c_freq_mode = <1>; + has_pdaf = <0>; + has_rs = <1>; + has_multi_output = <0>; + has_super_slow = <0>; + has_sub_sensor = <0>; + has_aube = <0>; + has_flicker_detector = <0>; + has_hdr = <0>; + has_seamless_mode_change = <0>; + has_gph = <1>; + pdaf_free_area_num = <0>; + pdaf_fixed_area_size_w = <0>; + pdaf_fixed_area_size_h = <0>; + pll_num = <26>; + pll = <1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134>; + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VDIG_GPIO", + "CAM_VDIG", + "CAM_VIO", + "CAM_VIO_GPIO", + "CAM_VAF", + "EXIT"; + CAM_VDIG = <0 0xFFFFFFFF 0 2>; + CAM_VIO = <1 0xFFFFFFFF 0 2>; + CAM_VIO_GPIO = <7 0xFFFFFFFF 0 28>; + CAM_VAF = <3 0xFFFFFFFF 0 2>; + GPIO_RESET = <5 0x0 0 5>; + CAM_VDIG_GPIO = <6 0xFFFFFFFF 0 5>; + CAM_CLK = <10 0xFFFFFFFF 0 0>; + EXIT = <12 0x0 0 0>; + }; + power_on { + commands = + "CAM_VDIG", + "CAM_VIO", + "CAM_VIO_GPIO", + "CAM_VAF", + "CAM_VDIG_GPIO", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + CAM_VDIG = <0 1352 105000 0>; + CAM_VIO = <1 0 0 0>; + CAM_VIO_GPIO = <7 0 0 1>; + CAM_VAF = <3 2700 150000 0>; + GPIO_RESET = <5 1 0 1>; + CAM_VDIG_GPIO = <6 0 0 1>; + CAM_CLK = <10 0 0 1>; + EXIT = <12 0x0 0 0>; + }; + }; + SOI13BS1 { + mount_angle = <270>; + sensor_rotation = <180>; + sensor_facing = <1>; + sensor_config_delay_num = <12>; + sensor_config_delay = <3 3 3 3 3 3 3 3 3 3 3 3>; + temperature_check_skip_num = <8>; + total_pixel_number_w = <4224>; + total_pixel_number_h = <3192>; + active_pixel_number_x = <8>; + active_pixel_number_y = <56>; + active_pixel_number_w = <4208>; + active_pixel_number_h = <3120>; + min_focus_distance = <100>; + hyper_focal_distance = <2000>; + diagonal_len = "5.867"; + unit_cell_size_w = "1.12"; + unit_cell_size_h = "1.12"; + min_f_number = "2.00"; + max_f_number = "2.00"; + min_focus_pos = <1>; + max_focus_pos = <1024>; + min_focus_dac = <0x0000>; + max_focus_dac = <0x03FF>; + focus_inf_range_offset = <0x24>; + focus_macro_range_offset = <0x24>; + focus_lens_stroke_inf_to_1m = <0x09>; + focus_lens_stroke_1m_to_macro = <0x55>; + focus_lens_stroke_inf_to_macro = <0x5E>; + focus_calc_type = <0x01>; + focus_wob_time = <0>; + has_3a = <0>; + has_focus_actuator = <1>; + need_standby_af = <0>; + i2c_freq_mode = <1>; + has_pdaf = <0>; + has_rs = <1>; + has_multi_output = <0>; + has_super_slow = <0>; + has_sub_sensor = <0>; + has_aube = <0>; + has_flicker_detector = <0>; + has_hdr = <0>; + has_seamless_mode_change = <0>; + has_gph = <1>; + pdaf_free_area_num = <0>; + pdaf_fixed_area_size_w = <0>; + pdaf_fixed_area_size_h = <0>; + pll_num = <26>; + pll = <1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134>; + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VDIG_GPIO", + "CAM_VDIG", + "CAM_VIO", + "CAM_VIO_GPIO", + "CAM_VAF", + "EXIT"; + CAM_VDIG = <0 0xFFFFFFFF 0 2>; + CAM_VIO = <1 0xFFFFFFFF 0 2>; + CAM_VIO_GPIO = <7 0xFFFFFFFF 0 1>; + CAM_VAF = <3 0xFFFFFFFF 0 2>; + GPIO_RESET = <5 0x0 0 5>; + CAM_VDIG_GPIO = <6 0xFFFFFFFF 0 5>; + CAM_CLK = <10 0xFFFFFFFF 0 0>; + EXIT = <12 0x0 0 0>; + }; + power_on { + commands = + "CAM_VDIG", + "CAM_VIO", + "CAM_VIO_GPIO", + "CAM_VAF", + "CAM_VDIG_GPIO", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + CAM_VDIG = <0 1352 105000 0>; + CAM_VIO = <1 0 0 0>; + CAM_VIO_GPIO = <7 0 0 1>; + CAM_VAF = <3 2700 150000 0>; + GPIO_RESET = <5 1 0 1>; + CAM_VDIG_GPIO = <6 0 0 1>; + CAM_CLK = <10 0 0 1>; + EXIT = <12 0x0 0 0>; + }; + }; + SEM13BS1 { + mount_angle = <270>; + sensor_rotation = <180>; + sensor_facing = <1>; + sensor_config_delay_num = <12>; + sensor_config_delay = <3 3 3 3 3 3 3 3 3 3 3 3>; + temperature_check_skip_num = <8>; + total_pixel_number_w = <4224>; + total_pixel_number_h = <3192>; + active_pixel_number_x = <8>; + active_pixel_number_y = <56>; + active_pixel_number_w = <4208>; + active_pixel_number_h = <3120>; + min_focus_distance = <100>; + hyper_focal_distance = <2000>; + diagonal_len = "5.867"; + unit_cell_size_w = "1.12"; + unit_cell_size_h = "1.12"; + min_f_number = "2.00"; + max_f_number = "2.00"; + min_focus_pos = <1>; + max_focus_pos = <1024>; + min_focus_dac = <0x0000>; + max_focus_dac = <0x03FF>; + focus_inf_range_offset = <0x24>; + focus_macro_range_offset = <0x24>; + focus_lens_stroke_inf_to_1m = <0x09>; + focus_lens_stroke_1m_to_macro = <0x53>; + focus_lens_stroke_inf_to_macro = <0x5C>; + focus_calc_type = <0x01>; + focus_wob_time = <0>; + has_3a = <0>; + has_focus_actuator = <1>; + need_standby_af = <0>; + i2c_freq_mode = <1>; + has_pdaf = <0>; + has_rs = <1>; + has_multi_output = <0>; + has_super_slow = <0>; + has_sub_sensor = <0>; + has_aube = <0>; + has_flicker_detector = <0>; + has_hdr = <0>; + has_seamless_mode_change = <0>; + has_gph = <1>; + pdaf_free_area_num = <0>; + pdaf_fixed_area_size_w = <0>; + pdaf_fixed_area_size_h = <0>; + pll_num = <26>; + pll = <1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134>; + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VDIG_GPIO", + "CAM_VDIG", + "CAM_VIO", + "CAM_VIO_GPIO", + "CAM_VAF", + "EXIT"; + CAM_VDIG = <0 0xFFFFFFFF 0 2>; + CAM_VIO = <1 0xFFFFFFFF 0 2>; + CAM_VIO_GPIO = <7 0xFFFFFFFF 0 1>; + CAM_VAF = <3 0xFFFFFFFF 0 2>; + GPIO_RESET = <5 0x0 0 5>; + CAM_VDIG_GPIO = <6 0xFFFFFFFF 0 5>; + CAM_CLK = <10 0xFFFFFFFF 0 0>; + EXIT = <12 0x0 0 0>; + }; + power_on { + commands = + "CAM_VDIG", + "CAM_VIO", + "CAM_VIO_GPIO", + "CAM_VAF", + "CAM_VDIG_GPIO", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + CAM_VDIG = <0 1352 105000 0>; + CAM_VIO = <1 0 0 0>; + CAM_VIO_GPIO = <7 0 0 1>; + CAM_VAF = <3 2700 150000 0>; + GPIO_RESET = <5 1 0 1>; + CAM_VDIG_GPIO = <6 0 0 1>; + CAM_CLK = <10 0 0 1>; + EXIT = <12 0x0 0 0>; + }; + }; +}; + +&qusb_phy0 { + qcom,efuse-offset = <0x00000005>; + qcom,qusb-phy-init-seq = + /* */ + <0x13 0x04 /* analog_controls_two */ + 0x7c 0x18c /* pll_clock_inverter */ + 0x80 0x2c /* pll_cmode */ + 0x0a 0x184 /* pll_lock_delay */ + 0xD0 0x21c /* imp_ctrl1 */ + 0x05 0x23c /* tune1 */ + 0x08 0x240 /* tune2 */ + 0xD4 0x244 /* tune3 */ + 0x04 0x248 /* tune4 */ + 0x19 0xb4>; /* digital_timers_two */ + + qcom,qusb-phy-host-init-seq = + /* */ + <0x63 0x210 /* pwr_ctrl1 */ + 0x13 0x04 /* analog_controls_two */ + 0x7c 0x18c /* pll_clock_inverter */ + 0x80 0x2c /* pll_cmode */ + 0x0a 0x184 /* pll_lock_delay */ + 0x8c 0x21c /* imp_ctrl1 */ + 0x05 0x23c /* tune1 */ + 0x03 0x240 /* tune2 */ + 0xff 0x218 /* rescode_contrpl */ + 0x62 0x210>; /* pwr_ctrl1 */ +}; + +&ssphy { + qcom,qmp-phy-init-seq = + /* */ + <0x138 0x30 0x00 + 0x034 0x04 0x01 + 0x080 0x14 0x00 + 0x03c 0x06 0x00 + 0x08c 0x08 0x00 + 0x15c 0x06 0x00 + 0x164 0x01 0x00 + 0x13c 0x80 0x00 + 0x0b0 0x82 0x00 + 0x0b8 0xab 0x00 + 0x0bc 0xea 0x00 + 0x0c0 0x02 0x00 + 0x060 0x06 0x00 + 0x068 0x16 0x00 + 0x070 0x36 0x00 + 0x0dc 0x00 0x00 + 0x0d8 0x3f 0x00 + 0x0f8 0x01 0x00 + 0x0f4 0xc9 0x00 + 0x148 0x0a 0x00 + 0x0a0 0x00 0x00 + 0x09c 0x34 0x00 + 0x098 0x15 0x00 + 0x090 0x04 0x00 + 0x154 0x00 0x00 + 0x094 0x00 0x00 + 0x0f0 0x00 0x00 + 0x00c 0x0a 0x00 + 0x048 0x07 0x00 + 0x0d0 0x80 0x00 + 0x184 0x01 0x00 + 0x010 0x01 0x00 + 0x01c 0x31 0x00 + 0x020 0x01 0x00 + 0x014 0x00 0x00 + 0x018 0x00 0x00 + 0x024 0x85 0x00 + 0x028 0x07 0x00 + 0x430 0x0b 0x00 + 0x4d4 0x0f 0x00 + 0x4d8 0x4e 0x00 + 0x4dc 0x18 0x00 + 0x4f8 0x07 0x00 + 0x4fc 0x80 0x00 + 0x504 0x43 0x00 + 0x50c 0x1c 0x00 + 0x434 0x75 0x00 + 0x43c 0x00 0x00 + 0x440 0x00 0x00 + 0x444 0x80 0x00 + 0x408 0x0a 0x00 + 0x414 0x06 0x00 + 0x500 0x00 0x00 + 0x4c0 0x03 0x00 + 0x564 0x05 0x00 + 0x830 0x0b 0x00 + 0x8d4 0x0f 0x00 + 0x8d8 0x4e 0x00 + 0x8dc 0x18 0x00 + 0x8f8 0x07 0x00 + 0x8fc 0x80 0x00 + 0x904 0x43 0x00 + 0x90c 0x1c 0x00 + 0x834 0x75 0x00 + 0x83c 0x00 0x00 + 0x840 0x00 0x00 + 0x844 0x80 0x00 + 0x808 0x0a 0x00 + 0x814 0x06 0x00 + 0x900 0x00 0x00 + 0x8c0 0x03 0x00 + 0x964 0x05 0x00 + 0x260 0x10 0x00 + 0x2a4 0x12 0x00 + 0x28c 0x16 0x00 + 0x244 0x00 0x00 + 0x660 0x10 0x00 + 0x6a4 0x12 0x00 + 0x68c 0x16 0x00 + 0x644 0x00 0x00 + 0xcc8 0x83 0x00 + 0xccc 0x09 0x00 + 0xcd0 0xa2 0x00 + 0xcd4 0x40 0x00 + 0xcc4 0x02 0x00 + 0xc80 0xd1 0x00 + 0xc84 0x1f 0x00 + 0xc88 0x47 0x00 + 0xc64 0x1b 0x00 + 0xc0c 0x9f 0x00 + 0xc10 0x9f 0x00 + 0xc14 0xb7 0x00 + 0xc18 0x4e 0x00 + 0xc1c 0x65 0x00 + 0xc20 0x6b 0x00 + 0xc24 0x15 0x00 + 0xc28 0x0d 0x00 + 0xc2c 0x15 0x00 + 0xc30 0x0d 0x00 + 0xc34 0x15 0x00 + 0xc38 0x0d 0x00 + 0xc3c 0x15 0x00 + 0xc40 0x0d 0x00 + 0xc44 0x15 0x00 + 0xc48 0x0d 0x00 + 0xc4c 0x15 0x00 + 0xc50 0x0d 0x00 + 0xc5c 0x02 0x00 + 0xca0 0x04 0x00 + 0xc8c 0x44 0x00 + 0xc70 0xe7 0x00 + 0xc74 0x03 0x00 + 0xc78 0x40 0x00 + 0xc7c 0x00 0x00 + 0xdd8 0x8a 0x00 + 0xcb8 0x75 0x00 + 0xcb0 0x86 0x00 + 0xcbc 0x13 0x00 + 0x21c 0x1f 0x00 + 0x61c 0x1f 0x00 + 0x20c 0x0c 0x00 + 0x60c 0x0c 0x00 + 0xffffffff 0xffffffff 0x00>; +}; + +&pm8998_gpios { + /* GPIO_1: UIM_BATT_ALARM */ + /* Follow QTI */ + + /* GPIO_2: NC */ + gpio@c100 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_3: WLAN_SW_CTRL */ + /* Follow QTI */ + + /* GPIO_4: SSC_PWR_EN */ + /* Follow QTI */ + + /* GPIO_5: VOL_DOWN_N */ + gpio@c400 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <0>; /* In */ + qcom,vin-sel = <0>; /* 1.8V */ + qcom,pull = <0>; /* PU */ + qcom,master-en = <1>; /* Enable */ + status = "ok"; + }; + + /* GPIO_6: VOL_UP_N */ + gpio@c500 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <0>; /* In */ + qcom,vin-sel = <0>; /* 1.8V */ + qcom,pull = <0>; /* PU */ + qcom,master-en = <1>; /* Enable */ + status = "ok"; + }; + + /* GPIO_7: SNAPSHOT_N */ + gpio@c600 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <0>; /* In */ + qcom,vin-sel = <0>; /* 1.8V */ + qcom,pull = <0>; /* PU */ + qcom,master-en = <1>; /* Enable */ + status = "ok"; + }; + + /* GPIO_8: FOCUS_N */ + gpio@c700 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <0>; /* In */ + qcom,vin-sel = <0>; /* 1.8V */ + qcom,pull = <0>; /* PU */ + qcom,master-en = <1>; /* Enable */ + status = "ok"; + }; + + /* GPIO_9: FLASH_THERM */ + gpio@c800 { + status = "ok"; + qcom,master-en = <0>; /* Disable */ + }; + + /* GPIO_13: DIV_CLK1 */ + /* Follow QTI */ + + /* GPIO_14: NC */ + gpio@cd00 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_15: NC */ + gpio@ce00 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_16: DIV_CLK3 */ + /* Follow QTI */ + + /* GPIO_17: NC */ + gpio@d000 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_18: NC */ + gpio@d100 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_19: NC */ + gpio@d200 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_20: NC */ + gpio@d300 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_21: NFC_CLK_REQ */ + gpio@d400 { + qcom,mode = <0>; /* In */ + qcom,vin-sel = <1>; /* 1.8V */ + qcom,pull = <4>; /* PD */ + qcom,master-en = <1>; /* Enable */ + status = "ok"; + }; + + /* GPIO_22: NC */ + gpio@d500 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_23: WCSS_PWR_REQ */ + /* Follow QTI */ + + /* GPIO_24: OPTION_1 */ + /* Follow QTI */ + + /* GPIO_25: OPTION_2 */ + /* Follow QTI */ + + /* GPIO_26: PM_SLB */ + /* Follow QTI */ +}; + +&pmi8998_gpios { + /* GPIO_1: NC */ + gpio@c000 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_2: NC */ + gpio@c100 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_3: NC */ + gpio@c200 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_4: TYPEC_UUSB_SEL */ + /* Follow QTI */ + + /* GPIO_5: VIB_LDO_EN */ + gpio@c400 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <1>; /* Out */ + qcom,output-type = <0>; /* CMOS */ + qcom,vin-sel = <0>; /* 1.8V */ + qcom,out-strength = <1>; /* Low */ + qcom,invert = <0>; /* Low */ + qcom,master-en = <1>; /* Enable */ + status = "okay"; + }; + + /* GPIO_6: NC */ + gpio@c500 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_7: DISPLAY_TYPE_SEL */ + /* Follow QTI */ + + /* GPIO_8: USB_SWITCH_SEL */ + gpio@c700 { + status = "okay"; + }; + + /* GPIO_9: NC */ + gpio@c800 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_10: 4K_DISP_DCDC_EN */ + gpio@c900 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <1>; /* Out */ + qcom,output-type = <0>; /* CMOS */ + qcom,vin-sel = <0>; /* 1.8V */ + qcom,out-strength = <1>; /* Low */ + qcom,invert = <0>; /* Low */ + qcom,master-en = <1>; /* Enable */ + status = "okay"; + }; + + /* GPIO_11: NC */ + gpio@ca00 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_12: DIV_CLK3 */ + /* Follow QTI */ + + /* GPIO_13: SPMI_I2C_SEL */ + /* Follow QTI */ + + /* GPIO_14: NC */ + gpio@cd00 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; +}; + +&pm8005_gpios { + /* GPIO_1: EAR_EN */ + gpio@c000 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <1>; /* Out */ + qcom,output-type = <0>; /* CMOS */ + qcom,vin-sel = <1>; /* 1.8V */ + qcom,out-strength = <1>; /* Low */ + qcom,invert = <0>; /* Low */ + qcom,master-en = <1>; /* Enable */ + status = "okay"; + }; + + /* GPIO_2: NC */ + gpio@c100 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_3: SLB */ + /* Follow QTI */ + + /* GPIO_4: OPTION_1_PM8005 */ + /* Follow QTI */ +}; + +&usb3 { + id_polling_use; + id_polling_up_interval = <2000>; + id_polling_up_period = <0>; + id_polling_pd_gpio = <&tlmm 128 0>; + qcom,usb_detect-vadc = <&pm8998_vadc>; +}; + +&pm8998_vadc { + chan@14 { /* USB_DETECT_ADC */ + label = "usb_detect"; + reg = <0x14>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <5>; + qcom,fast-avg-setup = <0>; + }; + + chan@4d { /* msm_therm */ + qcom,scale-function = <17>; + }; + + chan@4e { + label = "ufs_therm"; + reg = <0x4e>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <17>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@4f { + label = "pa_therm1"; + reg = <0x4f>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@50 { + label = "pa_therm2"; + reg = <0x50>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@51 { /* quiet_therm */ + qcom,scale-function = <17>; + }; + + chan@53 { + label = "flash_therm"; + reg = <0x53>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <17>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; +}; + +/* Regulator config */ +/* pm8998_s1 */ +/* Follow QTI */ + +/* pm8998_s2 */ +/* Follow QTI */ + +/* pm8998_s3 */ +/* Follow QTI */ + +/* pm8998_s4 */ +/* Follow QTI */ + +/* pm8998_s5 */ +/* Follow QTI */ + +/* pm8998_s6 */ +/* Follow QTI */ + +/* pm8998_s7 */ +/* Follow QTI */ + +/* pm8998_s8 */ +/* Follow QTI */ + +/* pm8998_s9 */ +/* Follow QTI */ + +/* pm8998_s10 */ +/* Follow QTI */ + +/* pm8998_s11 */ +/* Follow QTI */ + +/* pm8998_s12 */ +/* Follow QTI */ + +/* pm8998_s13 */ +/* Follow QTI */ + +/* pm8998_l1 */ +/* Follow QTI */ + +/* pm8998_l2 */ +/* Follow QTI */ + +/* pm8998_l3 */ +/* Follow QTI */ + +/* pm8998_l4 */ +/* Follow QTI */ + +/* pm8998_l5 */ +/* Follow QTI */ + +&pm8998_l6 { + qcom,regulator-type = <0>; /* LDO */ + qcom,init-enable = <0>; + qcom,init-ldo-mode = <1>; + qcom,init-pin-ctrl-enable = <0>; + qcom,init-pin-ctrl-mode = <0>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; +}; + +/* pm8998_l7 */ +/* Follow QTI */ + +/* pm8998_l8 */ +/* Follow QTI */ + +/* pm8998_l9 */ +/* Follow QTI */ + +/* pm8998_l10 */ +/* Follow QTI */ + +/* pm8998_l11 { +/* Follow QTI */ + +/* pm8998_l12 */ +/* Follow QTI */ + +/* pm8998_l13 */ +/* Follow QTI */ + +&pm8998_l14 { + qcom,regulator-type = <0>; /* LDO */ + qcom,init-enable = <0>; + qcom,init-ldo-mode = <1>; + qcom,init-pin-ctrl-enable = <0>; + qcom,init-pin-ctrl-mode = <0>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; +}; + +/* pm8998_l15 */ +/* Follow QTI */ + +/* pm8998_l16 */ +/* Follow QTI */ + +/* pm8998_l17 */ +/* Follow QTI */ + +&pm8998_l18 { + status = "disabled"; +}; + +&pm8998_l19 { + qcom,regulator-type = <0>; /* LDO */ + qcom,init-enable = <0>; + qcom,init-ldo-mode = <1>; + qcom,init-pin-ctrl-enable = <0>; + qcom,init-pin-ctrl-mode = <0>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + qcom,init-voltage = <2700000>; + status = "okay"; +}; + +/* pm8998_l20 */ +/* Follow QTI */ + +/* pm8998_l21 */ +/* Follow QTI */ + +&pm8998_l22 { + qcom,regulator-type = <0>; /* LDO */ + qcom,init-enable = <0>; + qcom,init-ldo-mode = <1>; + qcom,init-pin-ctrl-enable = <0>; + qcom,init-pin-ctrl-mode = <0>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + qcom,init-voltage = <2700000>; + status = "okay"; +}; + +/* pm8998_l23 */ +/* Follow QTI */ + +/* pm8998_l24 */ +/* Follow QTI */ + +/* pm8998_l25 */ +/* Follow QTI */ + +/* pm8998_l26 */ +/* Follow QTI */ + +/* pm8998_l27 */ +/* Follow QTI */ + +&pm8998_l28 { + qcom,regulator-type = <0>; /* LDO */ + qcom,init-enable = <0>; + qcom,init-ldo-mode = <1>; + qcom,init-pin-ctrl-enable = <0>; + qcom,init-pin-ctrl-mode = <0>; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <3000000>; + status = "okay"; +}; + +&pm8998_lvs1 { + qcom,regulator-type = <2>; /* VS */ + qcom,init-enable = <0>; + qcom,init-pin-ctrl-enable = <0>; + qcom,init-pin-ctrl-mode = <0>; + status = "okay"; +}; + +/* pm8998_lvs2 */ +/* Follow QTI */ + +/* pm8005_s1 */ +/* Follow QTI */ + +/* pm8005_s2 */ +/* Follow QTI */ + +/* pm8005_s3 */ +/* Follow QTI */ + +/* pm8005_s4 */ +/* Follow QTI */ + +/* pmi8998_bob */ +/* Follow QTI */ + +&tlmm { + /* GPIO_4 : DEBUG_UART_TX */ + msm_gpio_4: msm_gpio_4 { + mux { + pins = "gpio4"; + function = "blsp_uart8_a"; + }; + + config { + pins = "gpio4"; + drive-strength = <4>; + bias-disable; + }; + }; + + /* GPIO_5 : DEBUG_UART_RX */ + msm_gpio_5: msm_gpio_5 { + mux { + pins = "gpio5"; + function = "blsp_uart8_a"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + /* GPIO_6 : CAMSENSOR_I2C_SDA */ + msm_gpio_6: msm_gpio_6 { + mux { + pins = "gpio6"; + function = "blsp_i2c8"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; + bias-disable; + }; + }; + msm_gpio_6_suspend: msm_gpio_6_suspend { + mux { + pins = "gpio6"; + function = "blsp_i2c8"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_7 : CAMSENSOR_I2C_SCL */ + msm_gpio_7: msm_gpio_7 { + mux { + pins = "gpio7"; + function = "blsp_i2c8"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + msm_gpio_7_suspend: msm_gpio_7_suspend { + mux { + pins = "gpio7"; + function = "blsp_i2c8"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_8 : NC */ + msm_gpio_8: msm_gpio_8 { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_9 : "NC" */ + msm_gpio_9: msm_gpio_9 { + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_10 : MDP_VSYNC_P */ + msm_gpio_10: msm_gpio_10 { + mux { + pins = "gpio10"; + function = "mdp_vsync_a"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_11 : RGBC_IR_INT */ + msm_gpio_11: msm_gpio_11 { + mux { + pins = "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + msm_gpio_11_suspend: msm_gpio_11_suspend { + mux { + pins = "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_12 : NFC_VEN */ + msm_gpio_12: msm_gpio_12 { + mux { + pins = "gpio12"; + function = "gpio"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_13 : CAM_MCLK0 */ + msm_gpio_13: msm_gpio_13 { + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_14 : CAM_MCLK1 */ + msm_gpio_14: msm_gpio_14 { + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_15 : NC */ + msm_gpio_15: msm_gpio_15 { + mux { + pins = "gpio15"; + function = "gpio"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_16 : NC */ + msm_gpio_16: msm_gpio_16 { + mux { + pins = "gpio16"; + function = "gpio"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_17 : CCI_I2C_SDA0 */ + msm_gpio_17: msm_gpio_17 { + mux { + pins = "gpio17"; + function = "cci_i2c"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_18 : CCI_I2C_SCL0 */ + msm_gpio_18: msm_gpio_18 { + mux { + pins = "gpio18"; + function = "cci_i2c"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_19 : CCI_I2C_SDA1 */ + msm_gpio_19: msm_gpio_19 { + mux { + pins = "gpio19"; + function = "cci_i2c"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_20 : CCI_I2C_SCL1 */ + msm_gpio_20: msm_gpio_20 { + mux { + pins = "gpio20"; + function = "cci_i2c"; + }; + + config { + pins = "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_21 : MAIN_CAM_PWR_EN */ + msm_gpio_21: msm_gpio_21 { + /* CAMERA SENSOR 0 EN */ + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_22 : TOF_INT_N */ + msm_gpio_22: msm_gpio_22 { + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + msm_gpio_22_suspend: msm_gpio_22_suspend { + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_23 : NC */ + msm_gpio_23: msm_gpio_23 { + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_24 : NC */ + msm_gpio_24: msm_gpio_24 { + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_25 : CHAT_CAM_PWR_EN */ + msm_gpio_25: msm_gpio_25 { + /* CAMERA SENSOR 2 VDIG */ + mux { + /* CLK, DATA */ + pins = "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio25"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_26 : NC */ + msm_gpio_26: msm_gpio_26 { + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_27 : TOF_RESET_N */ + msm_gpio_27: msm_gpio_27 { + mux { + pins = "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio27"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_28 : CAM2_RSTN */ + msm_gpio_28: msm_gpio_28 { + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_29 : NC */ + msm_gpio_29: msm_gpio_29 { + mux { + pins = "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio29"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_30 : CAM1_RSTN */ + msm_gpio_30: msm_gpio_30 { + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_31 : NC */ + msm_gpio_31: msm_gpio_31 { + mux { + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_32 : NC */ + msm_gpio_32: msm_gpio_32 { + mux { + pins = "gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio32"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_33 : NC */ + msm_gpio_33: msm_gpio_33 { + mux { + pins = "gpio33"; + function = "gpio"; + }; + + config { + pins = "gpio33"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_34 : NC */ + msm_gpio_34: msm_gpio_34 { + mux { + pins = "gpio34"; + function = "gpio"; + }; + + config { + pins = "gpio34"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_35 : NC */ + msm_gpio_35: msm_gpio_35 { + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_36 : NC */ + msm_gpio_36: msm_gpio_36 { + mux { + pins = "gpio36"; + function = "gpio"; + }; + + config { + pins = "gpio36"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_37 : NC */ + msm_gpio_37: msm_gpio_37 { + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_38 : CC_DIR */ + /* Follow QTI */ + + /* GPIO_39 : UIM2_DETECT_EN */ + msm_gpio_39: msm_gpio_39 { + mux { + pins = "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio39"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_40 : FP_RESET_N */ + msm_gpio_40: msm_gpio_40 { + mux { + pins = "gpio40"; + function = "gpio"; + }; + + config { + pins = "gpio40"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_40 : FP_RESET_N, state device active */ + msm_gpio_40_output_high: msm_gpio_40_output_high { + mux { + pins = "gpio40"; + function = "gpio"; + }; + + config { + pins = "gpio40"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + /* GPIO_41 : NC */ + msm_gpio_41: msm_gpio_41 { + mux { + pins = "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio41"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_42 : NC */ + msm_gpio_42: msm_gpio_42 { + mux { + pins = "gpio42"; + function = "gpio"; + }; + + config { + pins = "gpio42"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_43 : NC */ + msm_gpio_43: msm_gpio_43 { + mux { + pins = "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_44 : NC */ + msm_gpio_44: msm_gpio_44 { + mux { + pins = "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio44"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_45 : BT_HCI_UART_TXD */ + /* Follow QTI */ + + /* GPIO_46 : BT_HCI_UART_RXD */ + /* Follow QTI */ + + /* GPIO_47 : BT_HCI_UART_CTS_N */ + /* Follow QTI */ + + /* GPIO_48 : BT_HCI_UART_RFR_N */ + /* Follow QTI */ + + /* GPIO_49 : NC */ + msm_gpio_49: msm_gpio_49 { + mux { + pins = "gpio49"; + function = "gpio"; + }; + + config { + pins = "gpio49"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_50 : NC */ + msm_gpio_50: msm_gpio_50 { + mux { + pins = "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio50"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_51 : NC */ + msm_gpio_51: msm_gpio_51 { + mux { + pins = "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio51"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_52 : NC */ + msm_gpio_52: msm_gpio_52 { + mux { + pins = "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio52"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_53 : CODEC_INT2_N */ + /* Follow QTI */ + + /* GPIO_54 : CODEC_INT1_N */ + /* Follow QTI */ + + /* GPIO_55 : APPS_I2C_SDA */ + msm_gpio_55: msm_gpio_55 { + mux { + pins = "gpio55"; + function = "blsp_i2c7"; + }; + + config { + pins = "gpio55"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_56 : APPS_I2C_SCL */ + msm_gpio_56: msm_gpio_56 { + mux { + pins = "gpio56"; + function = "blsp_i2c7"; + }; + + config { + pins = "gpio56"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_57 : FORCED_USB_BOOT */ + msm_gpio_57: msm_gpio_57 { + mux { + pins = "gpio57"; + function = "gpio"; + }; + + config { + pins = "gpio57"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_58 : NC */ + msm_gpio_58: msm_gpio_58 { + mux { + pins = "gpio58"; + function = "gpio"; + }; + + config { + pins = "gpio58"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_59 : NC */ + msm_gpio_59: msm_gpio_59 { + mux { + pins = "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio59"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_60 : NC */ + msm_gpio_60: msm_gpio_60 { + mux { + pins = "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio60"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_61 : NC */ + msm_gpio_61: msm_gpio_61 { + mux { + pins = "gpio61"; + function = "gpio"; + }; + + config { + pins = "gpio61"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_62 : NC */ + msm_gpio_62: msm_gpio_62 { + mux { + pins = "gpio62"; + function = "gpio"; + }; + + config { + pins = "gpio62"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_63 : TRAY2_DET_DS */ + msm_gpio_63: msm_gpio_63 { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + /* GPIO_64 : CODEC_RST_N */ + /* Follow QTI */ + + /* GPIO_65 : WSA_L_EN */ + msm_gpio_65: msm_gpio_65 { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_66 : WSA_R_EN */ + msm_gpio_66: msm_gpio_66 { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_67 : NC */ + msm_gpio_67: msm_gpio_67 { + mux { + pins = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_68 : NC */ + msm_gpio_68: msm_gpio_68 { + mux { + pins = "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio68"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_69 : NC */ + msm_gpio_69: msm_gpio_69 { + mux { + pins = "gpio69"; + function = "gpio"; + }; + + config { + pins = "gpio69"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_70 : LPASS_SLIMBUS_CLK */ + /* Follow QTI */ + + /* GPIO_71 : LPASS_SLIMBUS_DATA0 */ + /* Follow QTI */ + + /* GPIO_72 : LPASS_SLIMBUS_DATA1 */ + /* Follow QTI */ + + /* GPIO_73 : BT_FM_SLIMBUS_DATA */ + /* Follow QTI */ + + /* GPIO_74 : BT_FM_SLIMBUS_CLK */ + /* Follow QTI */ + + /* GPIO_75 : NC */ + msm_gpio_75: msm_gpio_75 { + mux { + pins = "gpio75"; + function = "gpio"; + }; + + config { + pins = "gpio75"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_76 : RF_LCD_ID_EN */ + msm_gpio_76: msm_gpio_76 { + mux { + pins = "gpio76"; + function = "gpio"; + }; + + config { + pins = "gpio76"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_77 : NC */ + msm_gpio_77: msm_gpio_77 { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_78 : NC */ + msm_gpio_78: msm_gpio_78 { + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_79 : NC */ + msm_gpio_79: msm_gpio_79 { + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_80 : NC */ + msm_gpio_80: msm_gpio_80 { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_81 : SW_SERVICE */ + msm_gpio_81: msm_gpio_81 { + mux { + pins = "gpio81"; + function = "gpio"; + }; + + config { + pins = "gpio81"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + + /* GPIO_82 : TX_GTR_THRES_IN */ + msm_gpio_82: msm_gpio_82 { + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_83 : HW_ID[0] */ + msm_gpio_83: msm_gpio_83 { + mux { + pins = "gpio83"; + function = "gpio"; + }; + + config { + pins = "gpio83"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + + /* GPIO_84 : HW_ID[1] */ + msm_gpio_84: msm_gpio_84 { + mux { + pins = "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio84"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + + /* GPIO_85 : NC */ + msm_gpio_85: msm_gpio_85 { + mux { + pins = "gpio85"; + function = "gpio"; + }; + + config { + pins = "gpio85"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_86 : NC */ + msm_gpio_86: msm_gpio_86 { + mux { + pins = "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio86"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_87 : TS_I2C_SDA */ + msm_gpio_87: msm_gpio_87 { + mux { + pins = "gpio87"; + function = "blsp_i2c5"; + }; + + config { + pins = "gpio87"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_88 : TS_I2C_SCL */ + msm_gpio_88: msm_gpio_88 { + mux { + pins = "gpio88"; + function = "blsp_i2c5"; + }; + + config { + pins = "gpio88"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_89 : TS_RESET */ + /* Follow QTI */ + + /* GPIO_90 : NC */ + msm_gpio_90: msm_gpio_90 { + mux { + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_91 : NC */ + msm_gpio_91: msm_gpio_91 { + mux { + pins = "gpio91"; + function = "gpio"; + }; + + config { + pins = "gpio91"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_92 : NFC_IRQ */ + msm_gpio_92: msm_gpio_92 { + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_93 : NFC_DWLD_EN */ + msm_gpio_93: msm_gpio_93 { + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_94 : DISP_RESET_N */ + msm_gpio_94: msm_gpio_94 { + mux { + pins = "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio94"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_95 : TRAY2_DET */ + msm_gpio_95: msm_gpio_95 { + mux { + pins = "gpio95"; + function = "gpio"; + }; + + config { + pins = "gpio95"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + /* GPIO_96 : CAM_SOF */ + msm_gpio_96: msm_gpio_96 { + mux { + pins = "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio96"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_97 : RFFE6_CLK */ + /* Follow QTI */ + + /* GPIO_98 : RFFE6_DATA */ + /* Follow QTI */ + + /* GPIO_99 : DEBUG_GPIO0 */ + msm_gpio_99: msm_gpio_99 { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_100 : DEBUG_GPIO1 */ + msm_gpio_100: msm_gpio_100 { + mux { + pins = "gpio100"; + function = "gpio"; + }; + + config { + pins = "gpio100"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_101 : GRFC4 */ + /* Follow QTI */ + + /* GPIO_102 : GRFC5 */ + /* Follow QTI */ + + /* GPIO_103 : GRFC6 */ + /* Follow QTI */ + + /* GPIO_104 : RSVD (GRFC7) */ + msm_gpio_104: msm_gpio_104 { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_105 : UIM2_DATA */ + /* Follow QTI */ + + /* GPIO_106 : UIM2_CLK */ + /* Follow QTI */ + + /* GPIO_107 : UIM2_RESET */ + /* Follow QTI */ + + /* GPIO_108 : UIM2_PRESENT (UIM2_DET) */ + msm_gpio_108: msm_gpio_108 { + mux { + pins = "gpio108"; + function = "gpio"; + }; + + config { + pins = "gpio108"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + /* GPIO_109 : UIM1_DATA */ + /* Follow QTI */ + + /* GPIO_110 : UIM1_CLK */ + /* Follow QTI */ + + /* GPIO_111 : UIM1_RST */ + /* Follow QTI */ + + /* GPIO_112 : UIM1_PRESENT (TRAY1_DET) */ + msm_gpio_112: msm_gpio_112 { + mux { + pins = "gpio112"; + function = "gpio"; + }; + + config { + pins = "gpio112"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + /* GPIO_113 : UIM_BATT_ALARM */ + /* Follow QTI */ + + /* GPIO_114 : RSVD (GRFC8) */ + msm_gpio_114: msm_gpio_114 { + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_115 : GRFC9 */ + /* Follow QTI */ + + /* GPIO_116 : NC */ + msm_gpio_116: msm_gpio_116 { + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_117 : ACCEL_INT */ + /* Follow QTI */ + + /* GPIO_118 : GYRO_INT */ + /* Follow QTI */ + + /* GPIO_119 : COMPASS_INT */ + /* Follow QTI */ + + /* GPIO_120 : ALS_PROX_INT_N */ + msm_gpio_120: msm_gpio_120 { + mux { + pins = "gpio120"; + function = "gpio"; + }; + + config { + pins = "gpio120"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + /* GPIO_121 : FP_INT_N */ + msm_gpio_121: msm_gpio_121 { + mux { + pins = "gpio121"; + function = "gpio"; + }; + + config { + pins = "gpio121"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_122 : NC */ + msm_gpio_122: msm_gpio_122 { + mux { + pins = "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio122"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_123 : BAROMETER_INT */ + msm_gpio_123: msm_gpio_123 { + mux { + pins = "gpio123"; + function = "gpio"; + }; + + config { + pins = "gpio123"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_124 : ACC_COVER_OPEN */ + msm_gpio_124: msm_gpio_124 { + mux { + pins = "gpio124"; + function = "gpio"; + }; + + config { + pins = "gpio124"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + /* GPIO_125 : TS_INT_N */ + msm_gpio_125: msm_gpio_125 { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + + /* GPIO_126 : NC */ + msm_gpio_126: msm_gpio_126 { + mux { + pins = "gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio126"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_127 : GRFC3 */ + /* Follow QTI */ + + /* GPIO_128 : USB_DETECT_EN */ + msm_gpio_128: msm_gpio_128 { + mux { + pins = "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio128"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_129 : NC */ + msm_gpio_129: msm_gpio_129 { + mux { + pins = "gpio129"; + function = "gpio"; + }; + + config { + pins = "gpio129"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_130 : QLINK_REQUEST */ + /* Follow QTI */ + + /* GPIO_131 : QLINK_ENABLE */ + /* Follow QTI */ + + /* GPIO_132 : GRFC2 */ + /* Follow QTI */ + + /* GPIO_133 : NC */ + msm_gpio_133: msm_gpio_133 { + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_134 : WMSS_RESET_N */ + /* Follow QTI */ + + /* GPIO_135 : PA_INDICATOR_OR */ + /* Follow QTI */ + + /* GPIO_136 : GRFC1 */ + /* Follow QTI */ + + /* GPIO_137 : RFFE3_DATA */ + /* Follow QTI */ + + /* GPIO_138 : RFFE3_CLK */ + /* Follow QTI */ + + /* GPIO_139 : RFFE4_DATA */ + /* Follow QTI */ + + /* GPIO_140 : RFFE4_CLK */ + /* Follow QTI */ + + /* GPIO_141 : RFFE5_DATA */ + /* Follow QTI */ + + /* GPIO_142 : RFFE5_CLK */ + /* Follow QTI */ + + /* GPIO_143 : GNSS_EN */ + /* Follow QTI */ + + /* GPIO_144 : MSS_LTE_COXM_TXD */ + /* Follow QTI */ + + /* GPIO_145 : MSS_LTE_COXM_RXD */ + /* Follow QTI */ + + /* GPIO_146 : RFFE2_DATA */ + /* Follow QTI */ + + /* GPIO_147 : RFFE2_CLK */ + /* Follow QTI */ + + /* GPIO_148 : RFFE1_DATA */ + /* Follow QTI */ + + /* GPIO_149 : RFFE1_CLK */ + /* Follow QTI */ + + mdss_touch_active: mdss_touch_active { + mux { + pins = "gpio125"; + function = "gpio"; + }; + config { + pins = "gpio125"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + + mdss_touch_suspend: mdss_touch_suspend { + mux { + pins = "gpio125"; + function = "gpio"; + }; + config { + pins = "gpio125"; + drive-strength = <2>; + bias-pull-down; + }; + }; +}; + +&pmx_mdss { + mdss_dsi_active: mdss_dsi_active { + mux { + pins = "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio94"; + drive-strength = <2>; /* 2 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + mdss_dsi_suspend: mdss_dsi_suspend { + mux { + pins = "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio94"; + drive-strength = <2>; /* 2 mA */ + /delete-property/ bias-pull-down; + bias-disable = <0>; /* no pull */ + output-low; + }; + }; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi0 { + pinctrl-names = "mdss_default", "mdss_sleep", "mdss_touch_active", "mdss_touch_suspend"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + pinctrl-2 = <&mdss_touch_active>; + pinctrl-3 = <&mdss_touch_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 94 0>; + qcom,platform-touch-reset-gpio = <&tlmm 89 0>; + qcom,platform-touch-int-gpio = <&tlmm 125 0>; + qcom,platform-touch-vddio-gpio = <&tlmm 133 0>; + somc,disp-dcdc-en-gpio = <&pmi8998_gpios 10 0>; + /delete-property/ qcom,platform-bklight-en-gpio; + /delete-property/ qcom,panel-mode-gpio; +}; + +&mdss_dsi1 { + /delete-property/ qcom,panel-mode-gpio; +}; + +&labibb { + qcom,lab@de00 { + interrupts = <0x3 0xde 0x0 IRQ_TYPE_LEVEL_LOW>, + <0x3 0xde 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "lab_vreg_not_ok_interrupt", "lab-vreg-ok"; + }; + qcom,ibb@dc00 { + interrupts = <0x3 0xdc 0x0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "ibb_vreg_not_ok_interrupt"; + }; +}; + +&mdss_dp_ctrl { + status = "disabled"; +}; + +&sdhc_2 { + cd-gpios = <&tlmm 95 0x0>; +}; + +&spmi_bus { + qcom,pm8998@0 { + qcom,power-on@800 { + qcom,s3-src = "resin"; + qcom,pon_1 { + /delete-property/ qcom,support-reset; + /delete-property/ qcom,s1-timer; + /delete-property/ qcom,s2-timer; + /delete-property/ qcom,s2-type; + }; + qcom,pon_2 { + linux,code = <115>; + }; + qcom,pon_3 { + /delete-property/ qcom,support-reset; + /delete-property/ qcom,s1-timer; + /delete-property/ qcom,s2-timer; + /delete-property/ qcom,s2-type; + }; + }; + }; + + qcom,pmi8998@2 { + pmi8998_charger: qcom,qpnp-smb2 { + qcom,otg-cl-ua = <1000000>; + }; + }; + + qcom,pmi8998@3 { + qcom,leds@d000 { + status = "okay"; + qcom,rgb_sync = <1>; + }; + }; +}; + +&red_led { + somc,pwm-channel = <4>; + linux,name = "led:rgb_red"; + linux,default-trigger = "none"; + somc,color_variation_max_num = <4>; + somc,max_current = < + 18 511 511 + 19 511 511 + 20 511 511 + 21 511 511>; +}; +&green_led { + somc,pwm-channel = <3>; + linux,name = "led:rgb_green"; + linux,default-trigger = "none"; + somc,color_variation_max_num = <4>; + somc,max_current = < + 18 511 511 + 19 511 511 + 20 511 511 + 21 511 511>; +}; + +&blue_led { + somc,pwm-channel = <2>; + linux,name = "led:rgb_blue"; + linux,default-trigger = "none"; + somc,color_variation_max_num = <4>; + somc,max_current = < + 18 511 511 + 19 511 511 + 20 511 511 + 21 511 511>; +}; + +&pmi8998_wled { + linux,name = "wled"; + qcom,fs-curr-ua = <24000>; + qcom,led-strings-list = [00 01 02]; + somc,init-br-ua = <10000>; + somc-s1,br-power-save-ua = <800>; + somc,bl-scale-enabled; + somc,area_count_table_size = <0>; +}; + +&flash_led { + qcom,hw-strobe-option = <1>; +}; + +&pmi8998_flash0 { + qcom,current-ma = <625>; + qcom,max-current = <1000>; + qcom,hw-strobe-edge-trigger; + qcom,strobe-sel = <1>; + somc,sw-strobe-init; +}; + +&pmi8998_flash1 { + qcom,current-ma = <625>; + qcom,max-current = <1000>; + qcom,hw-strobe-edge-trigger; + qcom,strobe-sel = <1>; + somc,sw-strobe-init; +}; + +&pmi8998_flash2 { + status = "disabled"; +}; + +&pmi8998_torch0 { + qcom,current-ma = <120>; + qcom,max-current = <200>; + qcom,hw-strobe-edge-trigger; + qcom,strobe-sel = <1>; + somc,sw-strobe-init; +}; + +&pmi8998_torch1 { + qcom,current-ma = <120>; + qcom,max-current = <200>; + qcom,hw-strobe-edge-trigger; + qcom,strobe-sel = <1>; + somc,sw-strobe-init; +}; + +&pmi8998_torch2 { + status = "disabled"; +}; + +&pmi8998_switch0 { + qcom,led-mask = <3>; +}; + +&pmi8998_switch1 { + status = "disabled"; +}; + +&pmi8998_fg { + qcom,fg-delta-soc-thr = <1>; + qcom,fg-recharge-soc-thr = <95>; + qcom,fg-empty-voltage = <3100>; + qcom,fg-rsense-sel = <0>; + qcom,fg-jeita-thresholds = <5 10 45 55>; + qcom,slope-limit-temp-threshold = <100>; + qcom,slope-limit-coeffs = <1 1 1 1>; + qcom,fg-esr-tight-lt-filter-micro-pct = <30000>; + qcom,fg-esr-broad-lt-filter-micro-pct = <30000>; + qcom,cycle-counter-en; + qcom,cl-start-capacity = <15>; + qcom,cl-min-temp = <150>; + qcom,cl-max-temp = <450>; + qcom,fg-jeita-hyst-temp = <2>; + qcom,hold-soc-while-full; + qcom,cl-max-increment = <0>; + qcom,cl-max-decrement = <20>; + somc,therm-coeff-c1 = <199>; + somc,therm-coeff-c2 = <80>; + somc,therm-coeff-c3 = <255>; +}; + +&pmi8998_charger { + clock-names = "xo"; + clocks = <&clock_gcc clk_cxo_clk_src>; + usb_switch_sel = <&pmi8998_gpios 8 0>; + qcom,usb-icl-ua = <1500000>; + io-channels = <&pmi8998_rradc 2>, + <&pmi8998_rradc 3>, + <&pmi8998_rradc 4>, + <&pmi8998_rradc 8>, + <&pmi8998_rradc 10>; + io-channel-names = "skin_temp", + "usbin_i", + "usbin_v", + "charger_temp", + "charger_temp_max"; + somc,jeita-sw-ctrl-en; +}; + +&pmi8998_rradc { + somc,reg-cfg = + /* addr mask value */ + <0x83 0x07 0x04>, /* FG_ADC_RR_AUX_THERM_CFG */ + <0x88 0xFF 0xAF>, /* FG_ADC_RR_AUX_THERM_C1 */ + <0x89 0xFF 0x34>, /* FG_ADC_RR_AUX_THERM_C2 */ + <0x8A 0xFF 0xDF>, /* FG_ADC_RR_AUX_THERM_C3 */ + <0x8B 0xFF 0xA0>; /* FG_ADC_RR_AUX_THERM_HALF_RANGE */ +}; + +&slim_aud { + tasha_codec { + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + qcom,cdc-dmic-sample-rate = <2400000>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-yoshino-lilac_common.dtsi b/arch/arm/boot/dts/qcom/msm8998-yoshino-lilac_common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ddfeb4cf32c6d98f330c0451c0b8b93f55c6daa8 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-yoshino-lilac_common.dtsi @@ -0,0 +1,666 @@ +/* arch/arm64/boot/dts/qcom/msm8998-lilac_common.dtsi + * + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include "msm8998-yoshino-common.dtsi" +#include "dsi-panel-lilac.dtsi" + +&soc { + /* I2C: BLSP5 */ + i2c@c179000 { /* BLSP1 QUP5 */ + synaptics_clearpad@2c { + preset_x_max = <719>; + preset_y_max = <1279>; + + /* Stamina Mode */ + stamina_mode_supported = <0x80000003>; + + /* F01_RMI_CTRL05: Doze Holdoff */ + doze_default_time = <35>; + doze_glove_mode_time = <35>; + doze_cover_mode_time = <35>; + }; + }; + + somc_pinctrl: somc_pinctrl { + pinctrl-1 = <&msm_gpio_89 &msm_gpio_102 &msm_gpio_103 &msm_gpio_105 &msm_gpio_106 + &msm_gpio_107 &msm_gpio_115 &msm_gpio_127 &msm_gpio_132 &msm_gpio_136>; + }; + + qcom,cci@ca0c000 { + qcom,camera@1 { + /delete-property/ cam_vio-supply; + /delete-property/ cam_vaf-supply; + qcom,cam-vreg-name = "cam_vdig", "cam_vio_gpio", "cam_vdig_gpio"; + qcom,cam-vreg-type = <0 0 0>; + qcom,cam-vreg-min-voltage = <1352000 0 0>; + qcom,cam-vreg-max-voltage = <1352000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + sony,eeprom_type = <2>; + }; + }; + + mdss_dsi0_pll: qcom,mdss_dsi_pll@c994400 { + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + qcom,ssc-frequency-hz = <31500>; + qcom,ssc-ppm = <5000>; + }; + /* I2C : BLSP8 */ + i2c_8: i2c@c1b6000 { /* BLSP2 QUP2 */ + tcs3490@72 { + rgbcir_vdd-supply = <&pm8998_l22>; + rgbcir-vio-supply = <&cam_vio_verg>; + ams,rgbcir-vdd-supply = <1>; + ams,rgbcir-gpio-vdd = <0>; + ams,rgbcir-vio-supply = <1>; + }; + tof_sensor@52 { + tof_avdd-supply = <&pm8998_l22>; + sony,tof-avdd-supply = <1>; + }; + }; +}; + +&sony_camera_module_1 { + module_names = "GENERIC", "LGI08BS0", "CHI08BS0"; + default_module_name = "LGI08BS0"; + /delete-node/ SOI13BS1; + /delete-node/ SEM13BS1; + + GENERIC { + mount_angle = <90>; + sensor_rotation = <0>; + sensor_facing = <1>; + sensor_config_delay_num = <12>; + sensor_config_delay = <3 3 3 3 3 3 3 3 3 3 3 3>; + temperature_check_skip_num = <0>; + total_pixel_number_w = <3296>; + total_pixel_number_h = <2528>; + active_pixel_number_x = <8>; + active_pixel_number_y = <8>; + active_pixel_number_w = <3280>; + active_pixel_number_h = <2464>; + min_focus_distance = <0>; + hyper_focal_distance = <715>; + diagonal_len = "4.595"; + unit_cell_size_w = "1.12"; + unit_cell_size_h = "1.12"; + min_f_number = "2.4"; + max_f_number = "2.4"; + min_focus_pos = <1>; + max_focus_pos = <1024>; + min_focus_dac = <0x0000>; + max_focus_dac = <0x03FF>; + focus_inf_range_offset = <0x24>; + focus_macro_range_offset = <0x24>; + focus_lens_stroke_inf_to_1m = <0x09>; + focus_lens_stroke_1m_to_macro = <0x55>; + focus_lens_stroke_inf_to_macro = <0x5E>; + focus_calc_type = <0x01>; + focus_wob_time = <0>; + has_3a = <0>; + has_focus_actuator = <0>; + need_standby_af = <0>; + i2c_freq_mode = <1>; + has_pdaf = <0>; + has_rs = <1>; + has_multi_output = <0>; + has_super_slow = <0>; + has_sub_sensor = <0>; + has_aube = <0>; + has_flicker_detector = <0>; + has_hdr = <0>; + has_seamless_mode_change = <0>; + has_gph = <0>; + pdaf_free_area_num = <0>; + pdaf_fixed_area_size_w = <0>; + pdaf_fixed_area_size_h = <0>; + pll_num = <26>; + pll = <1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134>; + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VDIG_GPIO", + "CAM_VDIG", + "CAM_VIO_GPIO", + "EXIT"; + CAM_VDIG = <0 0xFFFFFFFF 0 2>; + /delete-property/ CAM_VIO; + /delete-property/ CAM_VAF; + CAM_VIO_GPIO = <7 0xFFFFFFFF 0 1>; + GPIO_RESET = <5 0x0 0 5>; + CAM_VDIG_GPIO = <6 0xFFFFFFFF 0 5>; + CAM_CLK = <10 0xFFFFFFFF 0 0>; + EXIT = <12 0x0 0 0>; + }; + power_on { + commands = + "CAM_VDIG", + "CAM_VIO_GPIO", + "CAM_VDIG_GPIO", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + CAM_VDIG = <0 1352 105000 0>; + /delete-property/ CAM_VIO; + /delete-property/ CAM_VAF; + CAM_VIO_GPIO = <7 0 0 1>; + GPIO_RESET = <5 1 0 1>; + CAM_VDIG_GPIO = <6 0 0 1>; + CAM_CLK = <10 0 0 1>; + EXIT = <12 0x0 0 0>; + }; + }; + LGI08BS0 { + mount_angle = <90>; + sensor_rotation = <0>; + sensor_facing = <1>; + sensor_config_delay_num = <12>; + sensor_config_delay = <3 3 3 3 3 3 3 3 3 3 3 3>; + temperature_check_skip_num = <0>; + total_pixel_number_w = <3296>; + total_pixel_number_h = <2528>; + active_pixel_number_x = <8>; + active_pixel_number_y = <8>; + active_pixel_number_w = <3280>; + active_pixel_number_h = <2464>; + min_focus_distance = <0>; + hyper_focal_distance = <715>; + diagonal_len = "4.595"; + unit_cell_size_w = "1.12"; + unit_cell_size_h = "1.12"; + min_f_number = "2.4"; + max_f_number = "2.4"; + min_focus_pos = <1>; + max_focus_pos = <1024>; + min_focus_dac = <0x0000>; + max_focus_dac = <0x03FF>; + focus_inf_range_offset = <0x24>; + focus_macro_range_offset = <0x24>; + focus_lens_stroke_inf_to_1m = <0x09>; + focus_lens_stroke_1m_to_macro = <0x55>; + focus_lens_stroke_inf_to_macro = <0x5E>; + focus_calc_type = <0x01>; + focus_wob_time = <0>; + has_3a = <0>; + has_focus_actuator = <0>; + need_standby_af = <0>; + i2c_freq_mode = <1>; + has_pdaf = <0>; + has_rs = <1>; + has_multi_output = <0>; + has_super_slow = <0>; + has_sub_sensor = <0>; + has_aube = <0>; + has_flicker_detector = <0>; + has_hdr = <0>; + has_seamless_mode_change = <0>; + has_gph = <0>; + pdaf_free_area_num = <0>; + pdaf_fixed_area_size_w = <0>; + pdaf_fixed_area_size_h = <0>; + pll_num = <26>; + pll = <1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134>; + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VDIG_GPIO", + "CAM_VDIG", + "CAM_VIO_GPIO", + "EXIT"; + CAM_VDIG = <0 0xFFFFFFFF 0 2>; + CAM_VIO_GPIO = <7 0xFFFFFFFF 0 1>; + GPIO_RESET = <5 0x0 0 5>; + CAM_VDIG_GPIO = <6 0xFFFFFFFF 0 5>; + CAM_CLK = <10 0xFFFFFFFF 0 0>; + EXIT = <12 0x0 0 0>; + }; + power_on { + commands = + "CAM_VDIG", + "CAM_VIO_GPIO", + "CAM_VDIG_GPIO", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + CAM_VDIG = <0 1352 105000 0>; + CAM_VIO_GPIO = <7 0 0 1>; + GPIO_RESET = <5 1 0 1>; + CAM_VDIG_GPIO = <6 0 0 1>; + CAM_CLK = <10 0 0 1>; + EXIT = <12 0x0 0 0>; + }; + }; + CHI08BS0 { + mount_angle = <90>; + sensor_rotation = <0>; + sensor_facing = <1>; + sensor_config_delay_num = <12>; + sensor_config_delay = <3 3 3 3 3 3 3 3 3 3 3 3>; + temperature_check_skip_num = <0>; + total_pixel_number_w = <3296>; + total_pixel_number_h = <2528>; + active_pixel_number_x = <8>; + active_pixel_number_y = <8>; + active_pixel_number_w = <3280>; + active_pixel_number_h = <2464>; + min_focus_distance = <0>; + hyper_focal_distance = <715>; + diagonal_len = "4.595"; + unit_cell_size_w = "1.12"; + unit_cell_size_h = "1.12"; + min_f_number = "2.4"; + max_f_number = "2.4"; + min_focus_pos = <1>; + max_focus_pos = <1024>; + min_focus_dac = <0x0000>; + max_focus_dac = <0x03FF>; + focus_inf_range_offset = <0x24>; + focus_macro_range_offset = <0x24>; + focus_lens_stroke_inf_to_1m = <0x09>; + focus_lens_stroke_1m_to_macro = <0x55>; + focus_lens_stroke_inf_to_macro = <0x5E>; + focus_calc_type = <0x01>; + focus_wob_time = <0>; + has_3a = <0>; + has_focus_actuator = <0>; + need_standby_af = <0>; + i2c_freq_mode = <1>; + has_pdaf = <0>; + has_rs = <1>; + has_multi_output = <0>; + has_super_slow = <0>; + has_sub_sensor = <0>; + has_aube = <0>; + has_flicker_detector = <0>; + has_hdr = <0>; + has_seamless_mode_change = <0>; + has_gph = <0>; + pdaf_free_area_num = <0>; + pdaf_fixed_area_size_w = <0>; + pdaf_fixed_area_size_h = <0>; + pll_num = <26>; + pll = <1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134 1134>; + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VDIG_GPIO", + "CAM_VDIG", + "CAM_VIO_GPIO", + "EXIT"; + CAM_VDIG = <0 0xFFFFFFFF 0 2>; + CAM_VIO_GPIO = <7 0xFFFFFFFF 0 1>; + GPIO_RESET = <5 0x0 0 5>; + CAM_VDIG_GPIO = <6 0xFFFFFFFF 0 5>; + CAM_CLK = <10 0xFFFFFFFF 0 0>; + EXIT = <12 0x0 0 0>; + }; + power_on { + commands = + "CAM_VDIG", + "CAM_VIO_GPIO", + "CAM_VDIG_GPIO", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + CAM_VDIG = <0 1352 105000 0>; + CAM_VIO_GPIO = <7 0 0 1>; + GPIO_RESET = <5 1 0 1>; + CAM_VDIG_GPIO = <6 0 0 1>; + CAM_CLK = <10 0 0 1>; + EXIT = <12 0x0 0 0>; + }; + }; +}; + +&pm8998_gpios { + /* GPIO_20: DTV_PWR_EN */ + gpio@d300 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <1>; /* Out */ + qcom,output-type = <0>; /* CMOS */ + qcom,vin-sel = <1>; /* 1.8V */ + qcom,out-strength = <1>; /* Low */ + qcom,invert = <0>; /* Low */ + qcom,master-en = <1>; /* Enable */ + status = "okay"; + }; +}; + +&pmi8998_gpios { + /* GPIO_1: MAIN_CAM_PWR_IO_EN */ + gpio@c000 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <1>; /* Out */ + qcom,output-type = <0>; /* CMOS */ + qcom,vin-sel = <1>; /* 1.8V */ + qcom,out-strength = <1>; /* Low */ + qcom,invert = <0>; /* Low */ + qcom,master-en = <1>; /* Enable */ + status = "okay"; + }; + + /* GPIO_8: NC */ + gpio@c700 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_10: NC */ + gpio@c900 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; +}; + +&pm8005_gpios { + /* GPIO_1: NC */ + gpio@c000 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; +}; + +&usb3 { + dwc3@a800000 { + maximum-speed = "high-speed"; + }; +}; + +/* Regulator config */ +&pm8998_l22 { + qcom,regulator-type = <0>; /* LDO */ + qcom,init-enable = <0>; + qcom,init-ldo-mode = <1>; + qcom,init-pin-ctrl-enable = <0>; + qcom,init-pin-ctrl-mode = <0>; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + qcom,init-voltage = <2800000>; + status = "okay"; +}; + +&pm8998_lvs1 { + status = "disabled"; +}; + +&pmi8998_wled { + qcom,led-strings-list = [00 01]; + qcom,fs-curr-ua = <17500>; + somc,area_count_table_size = <21>; + somc,area_count_table = <0 137 273 410 546 683 819 956 + 1092 1229 1365 1638 1911 2184 2457 + 2730 3003 3276 3549 3822 4095>; + somc,init-br-ua = <8500>; +}; + +&red_led { + somc,color_variation_max_num = <4>; + somc,max_current = < + 34 510 419 + 35 498 348 + 36 498 348 + 37 498 348>; +}; + +&green_led { + somc,color_variation_max_num = <4>; + somc,max_current = < + 34 400 500 + 35 360 500 + 36 360 500 + 37 360 500>; +}; + +&blue_led { + somc,color_variation_max_num = <4>; + somc,max_current = < + 34 510 290 + 35 500 228 + 36 500 228 + 37 500 228>; +}; + +&tlmm { + /* GPIO_89 : TS_RESET_N */ + msm_gpio_89: msm_gpio_89 { + mux { + pins = "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio89"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_102 : NC */ + msm_gpio_102: msm_gpio_102{ + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_103 : NC */ + msm_gpio_103: msm_gpio_103{ + mux { + pins = "gpio103"; + function = "gpio"; + }; + + config { + pins = "gpio103"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_105 : NC */ + msm_gpio_105: msm_gpio_105{ + mux { + pins = "gpio105"; + function = "gpio"; + }; + + config { + pins = "gpio105"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_106 : NC */ + msm_gpio_106: msm_gpio_106{ + mux { + pins = "gpio106"; + function = "gpio"; + }; + + config { + pins = "gpio106"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_107 : NC */ + msm_gpio_107: msm_gpio_107{ + mux { + pins = "gpio107"; + function = "gpio"; + }; + + config { + pins = "gpio107"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_115 : NC */ + msm_gpio_115: msm_gpio_115{ + mux { + pins = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_127 : NC */ + msm_gpio_127: msm_gpio_127{ + mux { + pins = "gpio127"; + function = "gpio"; + }; + + config { + pins = "gpio127"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_132: NC */ + msm_gpio_132: msm_gpio_132{ + mux { + pins = "gpio132"; + function = "gpio"; + }; + + config { + pins = "gpio132"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_136: NC */ + msm_gpio_136: msm_gpio_136{ + mux { + pins = "gpio136"; + function = "gpio"; + }; + + config { + pins = "gpio136"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_default_panel>; +}; + +&mdss_dsi1 { + status = "disabled"; + /delete-property/ qcom,dsi-pref-prim-pan; +}; + +&vendor { + yoshino_lilac_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <17>; + #include "fg-gen3-batterydata-lilac-send-4380mv-2729mah.dtsi" + #include "fg-gen3-batterydata-lilac-send-4357mv-2688mah.dtsi" + #include "fg-gen3-batterydata-lilac-send-4335mv-2647mah.dtsi" + }; +}; + +&pmi8998_fg { + qcom,battery-data = <&yoshino_lilac_batterydata>; + qcom,fg-sys-term-current = <(-160)>; + qcom,fg-chg-term-current = <135>; + somc,rated-capacity-uah = <2650000>; + somc,initial-capacity-uah = <2820000>; +}; + +&pmi8998_charger { + qcom,fv-max-uv = <4380000>; + somc,product-icl-ua = <2000000>; + somc,high-voltage-icl-ua = <1700000>; + somc,thermal-fcc-ua = <2025000 2000000 1950000 + 1800000 1500000 1300000 + 1300000 1000000 800000 + 700000 700000 500000 + 300000 100000 0>; + somc,thermal-lo-volt-icl-ua = <2000000 1500000 1500000 + 1500000 1300000 1100000 + 1100000 1000000 900000 + 900000 900000 500000 + 200000 100000 0>; + somc,thermal-hi-volt-icl-ua = <1700000 1700000 1700000 + 1700000 1500000 1500000 + 1000000 1000000 1000000 + 1000000 600000 500000 + 200000 100000 0>; + somc,jeita-use-aux-therm; + somc,jeita-aux-thresh-hot = <530>; + somc,jeita-aux-thresh-warm = <430>; + somc,jeita-warm-fcc-ua = <800000>; + somc,jeita-cool-fcc-ua = <800000>; +}; + +&pmi8998_pdphy { + qcom,default-sink-caps = <5000 2000>, /* 5V @ 2A */ + <9000 1700>; /* 9V @ 1.7A */ +}; + +&spmi_bus { + qcom,pmi8998@3 { + labibb: qpnp-labibb-regulator { + ibb_regulator: qcom,ibb@dc00 { + qcom,qpnp-ibb-slew-rate = <12000>; + }; + lab_regulator: qcom,lab@de00 { + qcom,qpnp-lab-slew-rate = <5000>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-yoshino-lilac_generic.dts b/arch/arm/boot/dts/qcom/msm8998-yoshino-lilac_generic.dts new file mode 100644 index 0000000000000000000000000000000000000000..9874839a7bd5fe3ff7c490dd9be8f055f1eeeba3 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-yoshino-lilac_generic.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +/dts-v1/; + +#include "msm8998.dtsi" +#include "msm8998-mdss-panels.dtsi" +#include "msm8998-mtp.dtsi" +#include "msm8998-yoshino-lilac_generic.dtsi" + +/ { + model = "SoMC Lilac-ROW(MSM8998)"; + compatible = "somc,lilac-row", "qcom,msm8998"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-yoshino-lilac_generic.dtsi b/arch/arm/boot/dts/qcom/msm8998-yoshino-lilac_generic.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4d6ead4ebafda4c2a0dfe1e772e08ed7858ac4dc --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-yoshino-lilac_generic.dtsi @@ -0,0 +1,64 @@ +/* arch/arm64/boot/dts/qcom/msm8998-lilac_generic.dtsi + * + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include "msm8998-yoshino-lilac_common.dtsi" + +&soc { + /* I2C : BLSP7 */ + i2c@c1b5000 { /* BLSP2 QUP1 */ + nfc@28 { + compatible = "nxp,pn547"; + reg = <0x28>; + interrupt-parent = <&tlmm>; + interrupts = <92 0x1>; + nxp,irq_gpio = <&tlmm 92 0x00>; + nxp,dwld_en = <&tlmm 93 0x00>; + nxp,ven = <&tlmm 12 0x01>; + qcom,clk-src = "BBCLK2"; + qcom,clk-gpio = <&pm8998_gpios 21 0x00>; + clocks = <&clock_gcc clk_ln_bb_clk3_pin>; + clock-names = "nfc_clk"; + pinctrl-names = "pn547-active", "pn547-inactive"; + pinctrl-0 = <&msm_gpio_92 &msm_gpio_93>; + pinctrl-1 = <&msm_gpio_92 &msm_gpio_93>; + }; + }; + somc_pinctrl: somc_pinctrl { + /* If variant specific default setting is needed, + fill pinctrl-2 value in .dtsi */ + pinctrl-2 = <&msm_gpio_92>; + }; +}; + +&tlmm { + /* GPIO_92 : NFC_IRQ_FELICA_INT_N */ + msm_gpio_92: msm_gpio_92 { + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_common.dtsi b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6d5ce314357f8fff8c680c82d47651700f31afed --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_common.dtsi @@ -0,0 +1,423 @@ +/* arch/arm64/boot/dts/qcom/msm8998-poplar_common.dtsi + * + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include "msm8998-yoshino-common.dtsi" +#include "dsi-panel-poplar.dtsi" + +&soc { + /* I2C: BLSP5 */ + i2c@c179000 { /* BLSP1 QUP5 */ + synaptics_clearpad@2c { + preset_x_max = <1079>; + preset_y_max = <1919>; + + /* Stamina Mode */ + stamina_mode_supported = <0x80000003>; + + /* F01_RMI_CTRL05: Doze Holdoff */ + doze_default_time = <35>; + doze_glove_mode_time = <35>; + doze_cover_mode_time = <35>; + }; + }; + + somc_pinctrl: somc_pinctrl { + pinctrl-1 = <&msm_gpio_89 &msm_gpio_102 &msm_gpio_103 &msm_gpio_115 &msm_gpio_132 + &msm_gpio_133>; + }; + qcom,cci@ca0c000 { + qcom,camera@1 { + /delete-property/ cam_vio-supply; + qcom,cam-vreg-name = "cam_vaf", "cam_vdig", "cam_vio_gpio", "cam_vdig_gpio"; + qcom,cam-vreg-type = <0 0 0 0>; + qcom,cam-vreg-min-voltage = <2700000 1352000 0 0>; + qcom,cam-vreg-max-voltage = <2700000 1352000 0 0>; + qcom,cam-vreg-op-mode = <150000 105000 0 0>; + }; + }; + + mdss_dsi0_pll: qcom,mdss_dsi_pll@c994400 { + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + qcom,ssc-frequency-hz = <31500>; + qcom,ssc-ppm = <5000>; + }; +}; + +&sony_camera_module_1 { + GENERIC { + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VDIG_GPIO", + "CAM_VDIG", + "CAM_VIO_GPIO", + "CAM_VAF", + "EXIT"; + /delete-property/ CAM_VIO; + }; + power_on { + commands = + "CAM_VDIG", + "CAM_VIO_GPIO", + "CAM_VAF", + "CAM_VDIG_GPIO", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + /delete-property/ CAM_VIO; + }; + }; + SOI13BS1 { + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VDIG_GPIO", + "CAM_VDIG", + "CAM_VIO_GPIO", + "CAM_VAF", + "EXIT"; + /delete-property/ CAM_VIO; + }; + power_on { + commands = + "CAM_VDIG", + "CAM_VIO_GPIO", + "CAM_VAF", + "CAM_VDIG_GPIO", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + /delete-property/ CAM_VIO; + }; + }; + SEM13BS1 { + power_off { + commands = + "GPIO_RESET", + "CAM_CLK", + "CAM_VDIG_GPIO", + "CAM_VDIG", + "CAM_VIO_GPIO", + "CAM_VAF", + "EXIT"; + /delete-property/ CAM_VIO; + }; + power_on { + commands = + "CAM_VDIG", + "CAM_VIO_GPIO", + "CAM_VAF", + "CAM_VDIG_GPIO", + "CAM_CLK", + "GPIO_RESET", + "EXIT"; + /delete-property/ CAM_VIO; + }; + }; +}; + +&pmi8998_gpios { + /* GPIO_1: MAIN_CAM_PWR_IO_EN */ + gpio@c000 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <1>; /* Out */ + qcom,output-type = <0>; /* CMOS */ + qcom,vin-sel = <1>; /* 1.8V */ + qcom,out-strength = <1>; /* Low */ + qcom,invert = <0>; /* Low */ + qcom,master-en = <1>; /* Enable */ + status = "okay"; + }; +}; + +&pmi8998_gpios { + /* GPIO_1: MAIN_CAM_PWR_IO_EN */ + gpio@c000 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <1>; /* Out */ + qcom,output-type = <0>; /* CMOS */ + qcom,vin-sel = <1>; /* 1.8V */ + qcom,out-strength = <1>; /* Low */ + qcom,invert = <0>; /* Low */ + qcom,master-en = <1>; /* Enable */ + status = "okay"; + }; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_default_panel>; +}; + +&mdss_dsi1 { + status = "disabled"; + /delete-property/ qcom,dsi-pref-prim-pan; +}; + +&vendor { + yoshino_poplar_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <17>; + #include "fg-gen3-batterydata-poplar-send-4380mv-2650mah.dtsi" + #include "fg-gen3-batterydata-poplar-tdk-4380mv-2650mah.dtsi" + #include "fg-gen3-batterydata-poplar-send-4357mv-2688mah.dtsi" + #include "fg-gen3-batterydata-poplar-send-4335mv-2647mah.dtsi" + }; +}; + +&pmi8998_fg { + qcom,battery-data = <&yoshino_poplar_batterydata>; + qcom,fg-sys-term-current = <(-160)>; + qcom,fg-chg-term-current = <135>; + somc,rated-capacity-uah = <2650000>; + somc,initial-capacity-uah = <2792000>; +}; + +&pmi8998_charger { + qcom,fv-max-uv = <4380000>; + somc,product-icl-ua = <2000000>; + somc,high-voltage-icl-ua = <1700000>; + somc,thermal-fcc-ua = <2025000 2000000 1950000 + 1800000 1500000 1300000 + 1300000 1000000 800000 + 700000 700000 500000 + 300000 100000 0>; + somc,thermal-lo-volt-icl-ua = <2000000 1500000 1500000 + 1500000 1300000 1100000 + 1100000 1000000 900000 + 900000 900000 500000 + 200000 100000 0>; + somc,thermal-hi-volt-icl-ua = <1700000 1700000 1700000 + 1700000 1500000 1500000 + 1000000 1000000 1000000 + 1000000 600000 500000 + 200000 100000 0>; + somc,jeita-use-aux-therm; + somc,jeita-aux-thresh-hot = <900>; + somc,jeita-aux-thresh-warm = <700>; + somc,jeita-warm-fcc-ua = <800000>; + somc,jeita-cool-fcc-ua = <800000>; +}; + +&pmi8998_pdphy { + qcom,default-sink-caps = <5000 2000>, /* 5V @ 2A */ + <9000 1700>; /* 9V @ 1.7A */ +}; + +&pm8998_gpios { + /* GPIO_20: DTV_PWR_EN */ + gpio@d300 { + qcom,src-sel = <0>; /* GPIO */ + qcom,mode = <1>; /* Out */ + qcom,output-type = <0>; /* CMOS */ + qcom,vin-sel = <1>; /* 1.8V */ + qcom,out-strength = <1>; /* Low */ + qcom,invert = <0>; /* Low */ + qcom,master-en = <1>; /* Enable */ + status = "okay"; + }; +}; + +&pmi8998_gpios { + /* GPIO_8: NC */ + gpio@c700 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; + + /* GPIO_10: NC */ + gpio@c900 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; +}; + +&pm8005_gpios { + /* GPIO_1: NC */ + gpio@c000 { + qcom,master-en = <0>; /* Disable */ + status = "okay"; + }; +}; + +/* Regulator config */ +&pm8998_l18 { + qcom,regulator-type = <0>; /* LDO */ + qcom,init-enable = <1>; + qcom,init-ldo-mode = <1>; + qcom,init-pin-ctrl-enable = <0>; + qcom,init-pin-ctrl-mode = <0>; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + qcom,init-voltage = <2850000>; + regulator-always-on; + status = "okay"; +}; + +&pm8998_l22 { + qcom,regulator-type = <0>; /* LDO */ + qcom,init-enable = <0>; + qcom,init-ldo-mode = <1>; + qcom,init-pin-ctrl-enable = <0>; + qcom,init-pin-ctrl-mode = <0>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + qcom,init-voltage = <2700000>; + status = "okay"; +}; + +&tlmm { + /* GPIO_89 : TS_RESET_N */ + msm_gpio_89: msm_gpio_89 { + mux { + pins = "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio89"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* GPIO_102 : NC */ + msm_gpio_102: msm_gpio_102{ + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_103 : NC */ + msm_gpio_103: msm_gpio_103{ + mux { + pins = "gpio103"; + function = "gpio"; + }; + + config { + pins = "gpio103"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_115 : NC */ + msm_gpio_115: msm_gpio_115{ + mux { + pins = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_132: NC */ + msm_gpio_132: msm_gpio_132{ + mux { + pins = "gpio132"; + function = "gpio"; + }; + + config { + pins = "gpio132"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + /* GPIO_133: TS_VDDIO_EN*/ + msm_gpio_133: msm_gpio_133{ + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + drive-strength = <2>; + bias-disable; + }; + }; +}; + +&pmi8998_wled { + qcom,ilim-ma = <620>; + qcom,fs-curr-ua = <20000>; +}; + +&red_led { + somc,color_variation_max_num = <4>; + somc,max_current = < + 30 50 28 + 31 30 22 + 32 30 22 + 33 30 22>; +}; + +&green_led { + somc,color_variation_max_num = <4>; + somc,max_current = < + 30 18 28 + 31 16 30 + 32 16 30 + 33 16 30>; +}; + +&blue_led { + somc,color_variation_max_num = <4>; + somc,max_current = < + 30 56 12 + 31 44 12 + 32 52 12 + 33 44 12>; +}; + +&spmi_bus { + qcom,pmi8998@3 { + labibb: qpnp-labibb-regulator { + ibb_regulator: qcom,ibb@dc00 { + qcom,qpnp-ibb-slew-rate = <12000>; + }; + lab_regulator: qcom,lab@de00 { + qcom,qpnp-lab-slew-rate = <5000>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_dsds.dts b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_dsds.dts new file mode 100644 index 0000000000000000000000000000000000000000..c3fda1cd86dcfb2b76072c25a67c081b2fac82f1 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_dsds.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +/dts-v1/; + +#include "msm8998.dtsi" +#include "msm8998-mdss-panels.dtsi" +#include "msm8998-mtp.dtsi" +#include "msm8998-yoshino-poplar_dsds.dtsi" + +/ { + model = "SoMC Poplar-DSDS(MSM8998)"; + compatible = "somc,poplar-dsds", "qcom,msm8998"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_dsds.dtsi b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_dsds.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..663350fbf9e929351662fdd376ad525c1c1ea1fb --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_dsds.dtsi @@ -0,0 +1,35 @@ +/* arch/arm64/boot/dts/qcom/msm8998-yoshino-poplar_dsds.dtsi + * + * 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include "msm8998-yoshino-poplar_common.dtsi" +#include "msm8998-yoshino-poplar_generic.dtsi" + +&soc { + sim_detect { + sim2_det { + label = "sim2-detection"; + gpios = <&tlmm 63 0x0>; + debounce-interval = <10>; + }; + }; +}; + +&sdhc_2 { + uim2-gpios = <&tlmm 39 0x0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_generic.dts b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_generic.dts new file mode 100644 index 0000000000000000000000000000000000000000..ec1276fee7ac638ebed588c6b2e6deffd21f9a4e --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_generic.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +/dts-v1/; + +#include "msm8998.dtsi" +#include "msm8998-mdss-panels.dtsi" +#include "msm8998-mtp.dtsi" +#include "msm8998-yoshino-poplar_generic.dtsi" + +/ { + model = "SoMC Poplar-ROW(MSM8998)"; + compatible = "somc,poplar-row", "qcom,msm8998"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_generic.dtsi b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_generic.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d387cc33eabef917985ffd878898413350ae6830 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8998-yoshino-poplar_generic.dtsi @@ -0,0 +1,64 @@ +/* arch/arm64/boot/dts/qcom/msm8998-poplar_generic.dtsi + * + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include "msm8998-yoshino-poplar_common.dtsi" + +&soc { + /* I2C : BLSP7 */ + i2c@c1b5000 { /* BLSP2 QUP1 */ + nfc@28 { + compatible = "nxp,pn547"; + reg = <0x28>; + interrupt-parent = <&tlmm>; + interrupts = <92 0x1>; + nxp,irq_gpio = <&tlmm 92 0x00>; + nxp,dwld_en = <&tlmm 93 0x00>; + nxp,ven = <&tlmm 12 0x01>; + qcom,clk-src = "BBCLK2"; + qcom,clk-gpio = <&pm8998_gpios 21 0x00>; + clocks = <&clock_gcc clk_ln_bb_clk3_pin>; + clock-names = "nfc_clk"; + pinctrl-names = "pn547-active", "pn547-inactive"; + pinctrl-0 = <&msm_gpio_92 &msm_gpio_93>; + pinctrl-1 = <&msm_gpio_92 &msm_gpio_93>; + }; + }; + somc_pinctrl: somc_pinctrl { + /* If variant specific default setting is needed, + fill pinctrl-2 value in .dtsi */ + pinctrl-2 = <&msm_gpio_92>; + }; +}; + +&tlmm { + /* GPIO_92 : NFC_IRQ_FELICA_INT_N */ + msm_gpio_92: msm_gpio_92 { + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index 76e3282d327e28a76d58be2bf46fe2953e1d2dc1..e4daa8e3c6f1ca0e923650d98db5def8903aacef 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "skeleton64.dtsi" #include @@ -394,8 +399,8 @@ linux,cma-default; }; - cont_splash_mem: splash_region@9d600000 { - reg = <0x0 0x9d600000 0x0 0x02400000>; + cont_splash_mem: splash_region@9d400000 { + reg = <0x0 0x9d400000 0x0 0x02400000>; label = "cont_splash_mem"; }; }; @@ -1796,7 +1801,6 @@ tx-fifo-resize; snps,nominal-elastic-buffer; snps,disable-clk-gating; - snps,has-lpm-erratum; snps,hird-threshold = /bits/ 8 <0x10>; snps,num-gsi-evt-buffs = <0x3>; }; @@ -2173,6 +2177,7 @@ }; qcom,qbt1000 { + status = "disabled"; compatible = "qcom,qbt1000"; clock-names = "core", "iface"; clocks = <&clock_gcc clk_gcc_blsp2_qup6_spi_apps_clk>, @@ -2675,7 +2680,7 @@ 0x9ac 0x00 0x00 0x8a0 0x01 0x00 0x9e0 0x00 0x00 - 0x9dc 0x20 0x00 + 0x9dc 0x01 0x00 0x9a8 0x00 0x00 0x8a4 0x01 0x00 0x8a8 0x73 0x00 @@ -3106,8 +3111,6 @@ compatible = "qcom,wcn3990-wifi"; reg = <0x18800000 0x800000>; reg-names = "membase"; - clocks = <&clock_gcc clk_rf_clk2_pin>; - clock-names = "cxo_ref_clk_pin"; interrupts = <0 413 0 /* CE0 */ >, <0 414 0 /* CE1 */ >, @@ -3121,12 +3124,6 @@ <0 423 0 /* CE9 */ >, <0 424 0 /* CE10 */ >, <0 425 0 /* CE11 */ >; - vdd-0.8-cx-mx-supply = <&pm8998_l5>; - vdd-1.8-xo-supply = <&pm8998_l7_pin_ctrl>; - vdd-1.3-rfa-supply = <&pm8998_l17_pin_ctrl>; - vdd-3.3-ch0-supply = <&pm8998_l25_pin_ctrl>; - qcom,vdd-0.8-cx-mx-config = <800000 800000>; - qcom,vdd-3.3-ch0-config = <3104000 3312000>; }; qcom,icnss@18800000 { diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts index 0f4b462fd57ba3915312f74290ff240118f45cb3..604823ff416ee9511cd03bcfcaf91407874062d8 100644 --- a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts @@ -170,15 +170,6 @@ qcom,mdss-pref-prim-intf = "dsi"; }; -&mdss_dp_ctrl { - pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; - pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; - pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; - qcom,aux-en-gpio = <&tlmm 55 0>; - qcom,aux-sel-gpio = <&tlmm 56 0>; - qcom,usbplug-cc-gpio = <&tlmm 58 0>; -}; - &mdss_dsi { hw-config = "single_dsi"; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm630-camera-sensor-mtp.dtsi index 32a251f00550fde6e7c44202fee8d3c3399f4a2d..0275016c96622432d1ebd8e0ca6136cd084dad08 100644 --- a/arch/arm/boot/dts/qcom/sdm630-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-camera-sensor-mtp.dtsi @@ -114,26 +114,6 @@ status = "disabled"; }; - tof0: qcom,tof@29{ - cell-index = <0>; - reg = <0x29>; - compatible = "st,stmvl53l0"; - qcom,cci-master = <0>; - cam_laser-supply = <&pm660l_l8>; - qcom,cam-vreg-name = "cam_laser"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <3400000>; - qcom,cam-vreg-op-mode = <100000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_tof_active>; - pinctrl-1 = <&cam_tof_suspend>; - stm,irq-gpio = <&tlmm 45 0x2008>; - gpios = <&tlmm 42 0>; - qcom,gpio-req-tbl-num = <0>; - qcom,gpio-req-tbl-flags = <0>; - qcom,gpio-req-tbl-label = "RNG_EN"; - }; - eeprom0: qcom,eeprom@0 { cell-index = <0>; reg = <0>; diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index af3c5d1b51dadbb25f143d37418e382c4f5b1d5d..c24a41656f3ab4b988317fb58109683daa1eb557 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -399,9 +399,9 @@ &qusb_phy0 { qcom,qusb-phy-init-seq = <0xf8 0x80 - 0x83 0x84 + 0x80 0x84 0x83 0x88 - 0xc3 0x8c + 0xc7 0x8c 0x30 0x08 0x79 0x0c 0x21 0x10 diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 352e872c631fa098e2b04eb1c4b3e5ed6f2d89f6..a581e7cebc1d24759a3f3341acf99e222a4335c3 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -321,18 +321,6 @@ #size-cells = <2>; ranges; - wlan_msa_guard: wlan_msa_guard@85600000 { - compatible = "removed-dma-pool"; - no-map; - reg = <0x0 0x85600000 0x0 0x100000>; - }; - - wlan_msa_mem: wlan_msa_mem@85700000 { - compatible = "removed-dma-pool"; - no-map; - reg = <0x0 0x85700000 0x0 0x100000>; - }; - removed_region: removed_region0@85800000 { compatible = "removed-dma-pool"; no-map; @@ -613,7 +601,6 @@ compatible = "qcom,memshare-peripheral"; qcom,peripheral-size = <0x0>; qcom,client-id = <1>; - qcom,allocate-boot-time; label = "modem"; }; }; @@ -1166,9 +1153,8 @@ < 1113600 762 >, < 1344000 2086 >, < 1670400 2929 >, - < 1881600 3879 >, - < 2150400 4943 >, - < 2380800 5163 >; + < 2150400 3879 >, + < 2380800 4943 >; }; devfreq_memlat_4: qcom,arm-memlat-mon-4 { @@ -1366,6 +1352,7 @@ qcom,up-timer = <1000 1000>; qcom,down-timer = <1000 1000>; + qcom,pc-override-index = <0 0>; qcom,set-ret-inactive; qcom,enable-llm-freq-vote; qcom,llm-freq-up-timer = <327675 327675>; @@ -1427,7 +1414,6 @@ qcom,msm_fastrpc { compatible = "qcom,msm-fastrpc-adsp"; qcom,fastrpc-glink; - qcom,fastrpc-vmid-heap-shared; qcom,msm_fastrpc_compute_cb1 { compatible = "qcom,msm-fastrpc-compute-cb"; @@ -1682,7 +1668,6 @@ qcom,vdd-1.3-rfa-config = <1200000 1370000>; qcom,vdd-3.3-ch0-config = <3200000 3400000>; qcom,wlan-msa-memory = <0x100000>; - qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; qcom,smmu-s1-bypass; }; @@ -2032,7 +2017,6 @@ qcom,qsee-ce-hw-instance = <0>; qcom,disk-encrypt-pipe-pair = <2>; qcom,support-fde; - qcom,fde-key-size; qcom,no-clock-support; qcom,msm-bus,name = "qseecom-noc"; qcom,msm-bus,num-cases = <4>; diff --git a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-cdp.dtsi index 476fedec35a412800b74104e926621a80690b475..46f77e9a32530e85c16a19da97a8e319fabf12c7 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-cdp.dtsi @@ -29,16 +29,6 @@ qcom,switch-source = <&pm660l_switch1>; status = "ok"; }; - - cam_actuator_regulator: cam_actuator_fixed_regulator { - compatible = "regulator-fixed"; - regulator-name = "cam_actuator_regulator"; - regulator-min-microvolt = <3600000>; - regulator-max-microvolt = <3600000>; - enable-active-high; - gpio = <&tlmm 50 0>; - vin-supply = <&pm660l_bob>; - }; }; &cci { @@ -47,11 +37,14 @@ reg = <0x0>; compatible = "qcom,actuator"; qcom,cci-master = <0>; - cam_vaf-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - qcom,cam-vreg-op-mode = <0>; + gpios = <&tlmm 50 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; }; actuator1: qcom,actuator@1 { @@ -59,11 +52,14 @@ reg = <0x1>; compatible = "qcom,actuator"; qcom,cci-master = <1>; - cam_vaf-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - qcom,cam-vreg-op-mode = <0>; + gpios = <&tlmm 50 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; }; actuator2: qcom,actuator@2 { @@ -71,11 +67,14 @@ reg = <0x2>; compatible = "qcom,actuator"; qcom,cci-master = <1>; - cam_vaf-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - qcom,cam-vreg-op-mode = <0>; + gpios = <&tlmm 50 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; }; ois0: qcom,ois@0 { @@ -83,31 +82,15 @@ reg = <0x0>; compatible = "qcom,ois"; qcom,cci-master = <0>; - cam_vaf-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - qcom,cam-vreg-op-mode = <0>; - status = "disabled"; - }; - - tof0: qcom,tof@29{ - cell-index = <0>; - reg = <0x29>; - compatible = "st,stmvl53l0"; - qcom,cci-master = <0>; - cam_laser-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_laser"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_tof_active>; - pinctrl-1 = <&cam_tof_suspend>; - stm,irq-gpio = <&tlmm 45 0x2008>; - gpios = <&tlmm 42 0>; + gpios = <&tlmm 50 0>; + qcom,gpio-vaf = <0>; qcom,gpio-req-tbl-num = <0>; qcom,gpio-req-tbl-flags = <0>; - qcom,gpio-req-tbl-label = "RNG_EN"; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; + status = "disabled"; }; eeprom0: qcom,eeprom@0 { diff --git a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi index 11eb288804ff064fa57bd0f4ed26b80375f5d3a0..94166bf8dd3e35d026f6227a1450eb8c528c704a 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi @@ -40,16 +40,6 @@ vin-supply = <&pm660l_bob>; }; - cam_actuator_regulator: cam_actuator_fixed_regulator { - compatible = "regulator-fixed"; - regulator-name = "cam_actuator_regulator"; - regulator-min-microvolt = <3600000>; - regulator-max-microvolt = <3600000>; - enable-active-high; - gpio = <&tlmm 50 0>; - vin-supply = <&pm660l_bob>; - }; - cam_dvdd_gpio_regulator: cam_dvdd_fixed_regulator { compatible = "regulator-fixed"; regulator-name = "cam_dvdd_gpio_regulator"; @@ -77,11 +67,14 @@ reg = <0x0>; compatible = "qcom,actuator"; qcom,cci-master = <0>; - cam_vaf-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - qcom,cam-vreg-op-mode = <0>; + gpios = <&tlmm 50 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; }; actuator1: qcom,actuator@1 { @@ -89,11 +82,14 @@ reg = <0x1>; compatible = "qcom,actuator"; qcom,cci-master = <1>; - cam_vaf-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - qcom,cam-vreg-op-mode = <0>; + gpios = <&tlmm 50 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; }; actuator2: qcom,actuator@2 { @@ -101,11 +97,14 @@ reg = <0x2>; compatible = "qcom,actuator"; qcom,cci-master = <1>; - cam_vaf-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - qcom,cam-vreg-op-mode = <0>; + gpios = <&tlmm 50 0>; + qcom,gpio-vaf = <0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; }; ois0: qcom,ois@0 { @@ -113,31 +112,15 @@ reg = <0x0>; compatible = "qcom,ois"; qcom,cci-master = <0>; - cam_vaf-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - qcom,cam-vreg-op-mode = <0>; - status = "disabled"; - }; - - tof0: qcom,tof@29{ - cell-index = <0>; - reg = <0x29>; - compatible = "st,stmvl53l0"; - qcom,cci-master = <0>; - cam_laser-supply = <&cam_actuator_regulator>; - qcom,cam-vreg-name = "cam_laser"; - qcom,cam-vreg-min-voltage = <3600000>; - qcom,cam-vreg-max-voltage = <3600000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_tof_active>; - pinctrl-1 = <&cam_tof_suspend>; - stm,irq-gpio = <&tlmm 45 0x2008>; - gpios = <&tlmm 42 0>; + gpios = <&tlmm 50 0>; + qcom,gpio-vaf = <0>; qcom,gpio-req-tbl-num = <0>; qcom,gpio-req-tbl-flags = <0>; - qcom,gpio-req-tbl-label = "RNG_EN"; + qcom,gpio-req-tbl-label = "CAM_VAF"; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_actuator_vaf_active>; + pinctrl-1 = <&cam_actuator_vaf_suspend>; + status = "disabled"; }; eeprom0: qcom,eeprom@0 { diff --git a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi index 2194cf606d2977f0e44a84adfbdda471568dcc8a..fecb86dcfdeb0eee8d1f452a1243628e774eca5f 100644 --- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi @@ -506,51 +506,6 @@ qcom,bus-max = <0>; }; }; - - qcom,gpu-pwrlevels-4 { - #address-cells = <1>; - #size-cells = <0>; - - qcom,speed-bin = <78>; - - qcom,initial-pwrlevel = <1>; - - /* SVS */ - qcom,gpu-pwrlevel@0 { - reg = <0>; - qcom,gpu-freq = <370000000>; - qcom,bus-freq = <8>; - qcom,bus-min = <6>; - qcom,bus-max = <11>; - }; - - /* Low SVS */ - qcom,gpu-pwrlevel@1 { - reg = <1>; - qcom,gpu-freq = <266000000>; - qcom,bus-freq = <3>; - qcom,bus-min = <3>; - qcom,bus-max = <6>; - }; - - /* Min SVS */ - qcom,gpu-pwrlevel@2 { - reg = <2>; - qcom,gpu-freq = <160000000>; - qcom,bus-freq = <3>; - qcom,bus-min = <3>; - qcom,bus-max = <5>; - }; - - /* XO */ - qcom,gpu-pwrlevel@3 { - reg = <3>; - qcom,gpu-freq = <19200000>; - qcom,bus-freq = <0>; - qcom,bus-min = <0>; - qcom,bus-max = <0>; - }; - }; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi index 50f5d83346c6ebd043bf6c05fbbba4cc36f4c395..45b7201fbf71f5a3edfb7aa295028030ea2bb903 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi @@ -56,16 +56,6 @@ qcom,master-en = <1>; status = "okay"; }; - - /* GPIO 11 for Home Key */ - gpio@ca00 { - status = "okay"; - qcom,mode = <0>; - qcom,pull = <0>; - qcom,vin-sel = <0>; - qcom,src-sel = <0>; - qcom,out-strength = <1>; - }; }; &i2c_6 { /* BLSP1 QUP6 (NFC) */ diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index e55a67e68b36d611c57a7398fad9618106cad6f2..d902078b104858d3e7b8ba19d45c90da2741406b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -1101,34 +1101,6 @@ }; }; - cam_tof_active: cam_tof_active { - /* LASER */ - mux { - pins = "gpio50", "gpio42", "gpio45"; - function = "gpio"; - }; - - config { - pins = "gpio50", "gpio42", "gpio45"; - bias-pull-up; - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_tof_suspend: cam_tof_suspend { - /* LASER */ - mux { - pins = "gpio50", "gpio42", "gpio45"; - function = "gpio"; - }; - - config { - pins = "gpio50", "gpio42", "gpio45"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - }; - }; - cam_sensor_mclk0_active: cam_sensor_mclk0_active { /* MCLK0 */ mux { diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dts b/arch/arm/boot/dts/qcom/sdm660-qrd.dts index 28b7003539512b7802f31c4294bdce7d465a8197..4d120e83cb9bafb24d49baf08f016890895f932c 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dts @@ -28,15 +28,6 @@ qcom,mdss-pref-prim-intf = "dsi"; }; -&mdss_dp_ctrl { - pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; - pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; - pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; - qcom,aux-en-gpio = <&tlmm 55 0>; - qcom,aux-sel-gpio = <&tlmm 56 0>; - qcom,usbplug-cc-gpio = <&tlmm 58 0>; -}; - &mdss_fb0 { qcom,mdss-mixer-swap; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi index b1408cc295e8d8ab204c10cc133ec673bd862cdb..e78c2474df4d3ec05406aede67b54b4480b785f2 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi @@ -121,9 +121,9 @@ &qusb_phy0 { qcom,qusb-phy-init-seq = <0xf8 0x80 - 0x83 0x84 + 0x80 0x84 0x83 0x88 - 0xc3 0x8c + 0xc7 0x8c 0x30 0x08 0x79 0x0c 0x21 0x10 diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi index 6556c986ae753ec0fc03230be7793485d38d583a..a4111f6d1b94f52b350a48a0fa5602afd1bf586f 100644 --- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi @@ -700,33 +700,11 @@ regulator-max-microvolt = <8>; qcom,cpr-fuse-corners = <5>; - qcom,cpr-fuse-combos = <32>; - qcom,cpr-speed-bins = <4>; - qcom,cpr-speed-bin-corners = <8 8 0 8>; - qcom,cpr-corners = - /* Speed bin 0 */ - <8 8 8 8 8 8 8 8>, - - /* Speed bin 1 */ - <8 8 8 8 8 8 8 8>, - - /* Speed bin 2 */ - <0 0 0 0 0 0 0 0>, - - /* Speed bin 3 */ - <8 8 8 8 8 8 8 8>; - qcom,cpr-corner-fmax-map = - /* Speed bin 0 */ - <2 3 4 5 8>, - - /* Speed bin 1 */ - <2 3 4 5 8>, - - /* Speed bin 2 */ - <0 0 0 0 0>, - - /* Speed bin 3 */ - <2 3 4 5 8>; + qcom,cpr-fuse-combos = <16>; + qcom,cpr-speed-bins = <2>; + qcom,cpr-speed-bin-corners = <8 8>; + qcom,cpr-corners = <8>; + qcom,cpr-corner-fmax-map = <2 3 4 5 8>; qcom,cpr-voltage-ceiling = < 724000 724000 724000 788000 868000 @@ -737,20 +715,9 @@ 744000 784000 844000>; qcom,corner-frequencies = - /* Speed bin 0 */ - <300000000 633600000 902400000 - 1113600000 1401600000 1536000000 - 1747200000 1843200000>, - - /* Speed bin 1 */ - <300000000 633600000 902400000 - 1113600000 1401600000 1536000000 - 1747200000 1843200000>, - - /* Speed bin 3 */ <300000000 633600000 902400000 1113600000 1401600000 1536000000 - 1612800000 1843200000>; + 1747200000 1843200000>; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; @@ -839,34 +806,11 @@ regulator-max-microvolt = <7>; qcom,cpr-fuse-corners = <5>; - qcom,cpr-fuse-combos = <32>; - qcom,cpr-speed-bins = <4>; - qcom,cpr-speed-bin-corners = <7 7 0 7>; - qcom,cpr-corners = - /* Speed-bin 0 */ - <7 7 7 7 7 7 7 7>, - - /* Speed-bin 1 */ - <7 7 7 7 7 7 7 7>, - - /* Speed-bin 1 */ - <0 0 0 0 0 0 0 0>, - - /* Speed-bin 3 */ - <7 7 7 7 7 7 7 7>; - - qcom,cpr-corner-fmax-map = - /* Speed-bin 0 */ - <2 3 4 6 7>, - - /* Speed-bin 1 */ - <2 3 4 6 7>, - - /* Speed-bin 2 */ - <0 0 0 0 0>, - - /* Speed-bin 3 */ - <2 3 4 6 7>; + qcom,cpr-fuse-combos = <16>; + qcom,cpr-speed-bins = <2>; + qcom,cpr-speed-bin-corners = <7 7>; + qcom,cpr-corners = <7>; + qcom,cpr-corner-fmax-map = <2 3 4 6 7>; qcom,cpr-voltage-ceiling = <724000 724000 788000 868000 @@ -885,11 +829,6 @@ /* Speed bin 1 */ <300000000 1113600000 1401600000 1747200000 1958400000 2150400000 - 2208000000>, - - /* Speed bin 3 */ - <300000000 1113600000 1401600000 - 1747200000 1804800000 2150400000 2208000000>; qcom,allow-voltage-interpolation; diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index c626698ffd510431db8ff5802ae385d5960c4c2f..03537b1130269a28a5e9d58304379b5b1e79d75f 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -319,18 +319,6 @@ #size-cells = <2>; ranges; - wlan_msa_guard: wlan_msa_guard@85600000 { - compatible = "removed-dma-pool"; - no-map; - reg = <0x0 0x85600000 0x0 0x100000>; - }; - - wlan_msa_mem: wlan_msa_mem@85700000 { - compatible = "removed-dma-pool"; - no-map; - reg = <0x0 0x85700000 0x0 0x100000>; - }; - removed_regions: removed_regions@85800000 { compatible = "removed-dma-pool"; no-map; @@ -672,16 +660,6 @@ clock-names = "core", "iface"; }; - qcom,qbt1000 { - compatible = "qcom,qbt1000"; - clock-names = "core", "iface"; - clocks = <&clock_gcc GCC_BLSP1_QUP3_SPI_APPS_CLK>, - <&clock_gcc GCC_BLSP1_AHB_CLK>; - clock-frequency = <15000000>; - qcom,ipc-gpio = <&tlmm 72 0>; - qcom,finger-detect-gpio = <&pm660_gpios 11 0>; - }; - qcom,sensor-information { compatible = "qcom,sensor-information"; sensor_information0: qcom,sensor-information-0 { @@ -1254,11 +1232,10 @@ compatible = "qcom,clk-cpu-osm"; reg = <0x179c0000 0x4000>, <0x17916000 0x1000>, <0x17816000 0x1000>, <0x179d1000 0x1000>, - <0x00784130 0x8>, <0x00784130 0x8>, - <0x17914800 0x800>; + <0x00784130 0x8>, <0x17914800 0x800>; reg-names = "osm", "pwrcl_pll", "perfcl_pll", - "apcs_common", "pwrcl_efuse", - "perfcl_efuse", "pwrcl_acd"; + "apcs_common", "perfcl_efuse", + "pwrcl_acd"; qcom,acdtd-val = <0x0000a111 0x0000a111>; qcom,acdcr-val = <0x002c5ffd 0x002c5ffd>; @@ -1284,25 +1261,6 @@ < 1747200000 0x0404005b 0x09480048 0x2 7 >, < 1843200000 0x04040060 0x094c004c 0x3 8 >; - qcom,pwrcl-speedbin1-v0 = - < 300000000 0x0004000f 0x01200020 0x1 1 >, - < 633600000 0x05040021 0x03200020 0x1 2 >, - < 902400000 0x0404002f 0x04260026 0x1 3 >, - < 1113600000 0x0404003a 0x052e002e 0x2 4 >, - < 1401600000 0x04040049 0x073a003a 0x2 5 >, - < 1536000000 0x04040050 0x08400040 0x2 6 >, - < 1747200000 0x0404005b 0x09480048 0x2 7 >, - < 1843200000 0x04040060 0x094c004c 0x3 8 >; - - qcom,pwrcl-speedbin3-v0 = - < 300000000 0x0004000f 0x01200020 0x1 1 >, - < 633600000 0x05040021 0x03200020 0x1 2 >, - < 902400000 0x0404002f 0x04260026 0x1 3 >, - < 1113600000 0x0404003a 0x052e002e 0x2 4 >, - < 1401600000 0x04040049 0x073a003a 0x2 5 >, - < 1536000000 0x04040050 0x08400040 0x2 6 >, - < 1612800000 0x04040054 0x09430043 0x2 7 >; - qcom,perfcl-speedbin0-v0 = < 300000000 0x0004000f 0x01200020 0x1 1 >, < 1113600000 0x0404003a 0x052e002e 0x1 2 >, @@ -1321,13 +1279,6 @@ < 2150400000 0x04040070 0x0b590059 0x2 6 >, < 2208000000 0x04040073 0x0b5c005c 0x3 7 >; - qcom,perfcl-speedbin3-v0 = - < 300000000 0x0004000f 0x01200020 0x1 1 >, - < 1113600000 0x0404003a 0x052e002e 0x1 2 >, - < 1401600000 0x04040049 0x073a003a 0x2 3 >, - < 1747200000 0x0404005b 0x09480048 0x2 4 >, - < 1804800000 0x0404005e 0x094b004b 0x2 5 >; - qcom,up-timer = <1000 1000>; qcom,down-timer = <1000 1000>; qcom,pc-override-index = <0 0>; @@ -1381,7 +1332,6 @@ < 1113600 >, < 1401600 >, < 1536000 >, - < 1612800 >, < 1747200 >, < 1843200 >; @@ -1389,7 +1339,6 @@ < 1113600 >, < 1401600 >, < 1747200 >, - < 1804800 >, < 1958400 >, < 2150400 >, < 2208000 >, @@ -1606,7 +1555,6 @@ qcom,msm_fastrpc { compatible = "qcom,msm-fastrpc-adsp"; qcom,fastrpc-glink; - qcom,fastrpc-vmid-heap-shared; qcom,msm_fastrpc_compute_cb1 { compatible = "qcom,msm-fastrpc-compute-cb"; @@ -1980,7 +1928,6 @@ qcom,vdd-1.3-rfa-config = <1200000 1370000>; qcom,vdd-3.3-ch0-config = <3200000 3400000>; qcom,wlan-msa-memory = <0x100000>; - qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; qcom,smmu-s1-bypass; }; @@ -2085,7 +2032,6 @@ qcom,firmware-name = "modem"; qcom,pil-self-auth; qcom,sysmon-id = <0>; - qcom,minidump-id = <0>; qcom,ssctl-instance-id = <0x12>; qcom,qdsp6v62-1-5; memory-region = <&modem_fw_mem>; @@ -2160,11 +2106,6 @@ compatible = "qcom,msm-imem-diag-dload"; reg = <0xc8 200>; }; - - ss_mdump@b88 { - compatible = "qcom,msm-imem-minidump"; - reg = <0xb88 28>; - }; }; qcom,ghd { diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts index 30b36c0ac541f5c10a1aae341549b17c4744daeb..7cf55acf900ba0c77d37c695f63ff1375732adb5 100644 --- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts @@ -42,13 +42,6 @@ reg = <0x1 0x0 0 0x10000000>; label = "ion_system_mem"; }; - qseecom_mem: qseecom_region { - compatible = "shared-dma-pool"; - alloc-ranges = <0 0x00000000 0 0xffffffff>; - reusable; - alignment = <0 0x400000>; - size = <0 0x1400000>; - }; ion_audio: ion_audio_region { reg = <0 0xc8000000 0 0x00400000>; label = "ion_audio_mem"; @@ -85,10 +78,6 @@ <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, - <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, - <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, - <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, - <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, @@ -107,10 +96,6 @@ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", - "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", - "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", - "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", - "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", @@ -492,22 +477,6 @@ }; }; - qcom_seecom: qseecom@86600000 { - compatible = "qcom,qseecom"; - reg = <0x86600000 0x2200000>; - reg-names = "secapp-region"; - qcom,hlos-num-ce-hw-instances = <1>; - qcom,hlos-ce-hw-instance = <0>; - qcom,qsee-ce-hw-instance = <0>; - qcom,disk-encrypt-pipe-pair = <2>; - qcom,no-clock-support; - qcom,msm-bus,name = "qseecom-noc"; - qcom,msm-bus,num-cases = <4>; - qcom,msm-bus,num-paths = <1>; - qcom,ce-opp-freq = <171430000>; - qcom,qsee-reentrancy-support = <2>; - }; - hostless: qcom,msm-pcm-hostless { compatible = "qcom,msm-pcm-hostless"; }; diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig index fbd36cd00ea0c6a6b946ba03b19d2a83e41ba9d0..43b6432118f0c32395adced6cf9b431764f8c58d 100644 --- a/arch/arm/configs/sdm660-perf_defconfig +++ b/arch/arm/configs/sdm660-perf_defconfig @@ -93,7 +93,6 @@ CONFIG_XFRM_USER=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y -CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y @@ -616,9 +615,6 @@ CONFIG_EXT4_ENCRYPTION=y CONFIG_EXT4_FS_ENCRYPTION=y CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_EXT4_DEBUG=y -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -659,9 +655,7 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_SOURCE_DUMMY=y CONFIG_PFK=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y -CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_ECHAINIV=y diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig index 525dda6eb93e525897f6384fb25e235857b54ef2..e3aa35da81ce2b8e3059eaf7c229b95e6442f6fa 100644 --- a/arch/arm/configs/sdm660_defconfig +++ b/arch/arm/configs/sdm660_defconfig @@ -91,7 +91,6 @@ CONFIG_XFRM_USER=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y -CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y @@ -618,9 +617,6 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y CONFIG_EXT4_FS_ENCRYPTION=y CONFIG_EXT4_FS_ICE_ENCRYPTION=y -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -697,9 +693,7 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_SOURCE_DUMMY=y CONFIG_PFK=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y -CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_ECHAINIV=y diff --git a/arch/arm/include/asm/bitrev.h b/arch/arm/include/asm/bitrev.h index ec291c350ea3814e4f16e13140a324a0b509a531..2f3c9c488794db50b4a28abfbc1819589888bd9e 100644 --- a/arch/arm/include/asm/bitrev.h +++ b/arch/arm/include/asm/bitrev.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ #ifndef __ASM_BITREV_H #define __ASM_BITREV_H diff --git a/arch/arm/include/asm/crash_notes.h b/arch/arm/include/asm/crash_notes.h new file mode 100644 index 0000000000000000000000000000000000000000..421eed9c0aebbc195b3c5759c4f772056324887d --- /dev/null +++ b/arch/arm/include/asm/crash_notes.h @@ -0,0 +1,37 @@ +/* arch/arm/include/asm/crash_notes.h + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __ARM_CRASH_NOTES_H +#define __ARM_CRASH_NOTES_H + +static inline void crash_notes_save_regs(struct pt_regs *regs) +{ + __asm__ __volatile__ ( + "stmia %[regs_base], {r0-r12}\n\t" + "mov %[_ARM_sp], sp\n\t" + "str lr, %[_ARM_lr]\n\t" + "adr %[_ARM_pc], 1f\n\t" + "mrs %[_ARM_cpsr], cpsr\n\t" + "1:" + : [_ARM_pc] "=r" (regs->ARM_pc), + [_ARM_cpsr] "=r" (regs->ARM_cpsr), + [_ARM_sp] "=r" (regs->ARM_sp), + [_ARM_lr] "=o" (regs->ARM_lr) + : [regs_base] "r" (®s->ARM_r0) + : "memory" + ); +} + +#endif diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index f13ae153fb246b9d64f2c99f75a717b70c1e5a67..d2315ffd8f12658b5e45bfa5831538fc4e4ad1e4 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h @@ -112,8 +112,12 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs); #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE 4096 -/* This is the base location for PIE (ET_DYN with INTERP) loads. */ -#define ELF_ET_DYN_BASE 0x400000UL +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) /* When the program starts, a1 contains a pointer to a function to be registered with atexit, as per the SVR4 ABI. A value of 0 means we diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 7b8f2141427bda172899bfe8ae5113367163af47..c02613ed984981387cf0285f66d2b4fdf5ee6803 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -7,6 +7,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index d3d71877238196f61461f1731b42c030a9efccd8..30d1d04a047549901d0eb3523f03aca67a3c50a2 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -7,6 +7,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index f353849d93882a8e2c8e47d250a17a35072c5bd8..221b11bb50e360d6581d6ca1f83d578b07dffa57 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1197,15 +1197,15 @@ void __init sanity_check_meminfo(void) high_memory = __va(arm_lowmem_limit - 1) + 1; - if (!memblock_limit) - memblock_limit = arm_lowmem_limit; - /* * Round the memblock limit down to a pmd size. This * helps to ensure that we will allocate memory from the * last full pmd, which should be mapped. */ - memblock_limit = round_down(memblock_limit, PMD_SIZE); + if (memblock_limit) + memblock_limit = round_down(memblock_limit, PMD_SIZE); + if (!memblock_limit) + memblock_limit = arm_lowmem_limit; memblock_set_current_limit(memblock_limit); } diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 0c369a5d59f939dc8a7d47cbf4320411e02b1e89..3ee22e6146e9aac41ea7e225afdde904ac711ee0 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -6,6 +6,7 @@ config ARM64 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_GCOV_PROFILE_ALL + select ARCH_HAS_CRASH_NOTES if CRASH_NOTES select ARCH_HAS_SG_CHAIN select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_USE_CMPXCHG_LOCKREF @@ -893,6 +894,15 @@ config ARM64_LSE_ATOMICS not support these instructions and requires the kernel to be built with binutils >= 2.25. +config ARM64_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 config ARM64_UAO @@ -1081,6 +1091,17 @@ config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES Space separated list of names of dtbs to append when building a concatenated Image.gz-dtb. +config ARCH_HAS_CRASH_NOTES + bool + +config CRASH_NOTES + bool "Support storing crash notes at panic" + depends on !KEXEC + help + Generate kdump style crash notes at the time of a panic and fill it + with the crashed context to support analysis of the memory dump with + tools like Redhat CRASH. + config BUILD_ARM64_DT_OVERLAY bool "enable DT overlay compilation support" depends on OF diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index b6e5fa37f976f6baf0a5382e056fe6f1b002a866..2f2d2c317dc1fa7f640b5dac1c35bc31951ed04d 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -77,6 +77,42 @@ config ARCH_MSM8998 This enables support for the MSM8998 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. +config ARCH_SONY_YOSHINO + bool "Sony Mobile Yoshino platform" + depends on ARCH_MSM8998 + help + Support for the SONY Mobile Yoshino platform + which is based on QCOM MSM8998 chipset. + If you enable this config, + please use SONY Mobile device tree. + +config MACH_SONY_POPLAR + bool "Sony Mobile Poplar" + depends on ARCH_SONY_YOSHINO + help + Support for the SONY Mobile Poplar device + which is based on SONY Yoshino platform. + If you enable this config, + please use SONY Mobile device tree. + +config MACH_SONY_POPLAR_DSDS + bool "Sony Mobile Poplar Dsds" + depends on ARCH_SONY_YOSHINO + help + Support for the SONY Mobile Poplar Dsds device + which is based on SONY Yoshino platform. + If you enable this config, + please use SONY Mobile device tree. + +config MACH_SONY_LILAC + bool "Sony Mobile Lilac" + depends on ARCH_SONY_YOSHINO + help + Support for the SONY Mobile Lilac device + which is based on SONY Yoshino platform. + If you enable this config, + please use SONY Mobile device tree. + config ARCH_MSMHAMSTER bool "Enable Support for Qualcomm Technologies Inc MSMHAMSTER" depends on ARCH_QCOM diff --git a/arch/arm64/configs/diffconfig/common_diffconfig b/arch/arm64/configs/diffconfig/common_diffconfig new file mode 100644 index 0000000000000000000000000000000000000000..3004de27cd38ce7da9b18378bf3da7ab4800662c --- /dev/null +++ b/arch/arm64/configs/diffconfig/common_diffconfig @@ -0,0 +1,191 @@ +CONFIG_AHC=y +CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_STATS=y +CONFIG_ARCH_SONY_YOSHINO=y +CONFIG_ARM64_FLUSH_CONSOLE_ON_RESTART=y +CONFIG_CRASH_NOTES=y +# CONFIG_DEVPORT is not set +CONFIG_DYNAMIC_DEBUG=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL=y +CONFIG_FORCE_24BIT_COPP=y +CONFIG_FPC1145_PLATFORM=y +# CONFIG_GPIO_USB_DETECT is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_SONY=y +CONFIG_INPUT_BU520X1NVX=y +# CONFIG_INPUT_HBTP_INPUT is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_LAST_LOGS=y +CONFIG_LDO_VIBRATOR=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_MEMCG=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_CMD_DEBUG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK=y +CONFIG_NLS_UTF8=y +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_PANIC_ON_DM_VERITY_ERRORS=y +CONFIG_PINCTRL_SOMC=y +CONFIG_POWERKEY_FORCECRASH=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_PSTORE=y +CONFIG_QCOM_DCC=y +CONFIG_QCOM_RTB=y +CONFIG_QNS_SYSTEM=y +# CONFIG_QPNP_HAPTIC is not set +# CONFIG_QPNP_QNOVO is not set +CONFIG_RAMDUMP_MEMDESC=y +CONFIG_RAMDUMP_TAGS=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_KTHREAD_PRIO=1 +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_SCSI_UFS_RESTRICT_TX_LANES=y +CONFIG_SDCARD_FS=y +CONFIG_SECURITY_SELINUX_AVC_EXTRA_INFO=y +CONFIG_SECURITY_SELINUX_TRAP=y +CONFIG_SECURITY_STATUS=y +CONFIG_SERIAL_MSM=y +CONFIG_SIM_DETECT=y +CONFIG_SOMC_CHARGER_EXTENSION=y +CONFIG_SOMC_LCD_OCP_ENABLED=y +CONFIG_SONY_CAM_V4L2=y +CONFIG_STRICT_DEVMEM=y +CONFIG_SUBSYS_LAST_ERR_LOG=y +# CONFIG_TRACE_PRINTK is not set +CONFIG_UID_STAT=y +CONFIG_USB_DWC3_MSM_ID_POLL=y +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_HOST_EXTRA_NOTIFICATION=y +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OTG_WAKELOCK is not set +CONFIG_VFAT_FS_NO_DUALNAMES=y +CONFIG_WAKEUP_IRQ_DEBUG=y +CONFIG_XFRM_RFC_4868_TRUNCATION=y +CONFIG_Z3FOLD=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ARCH_HAS_CRASH_NOTES=y +# CONFIG_DVB_AS102 is not set +# CONFIG_DVB_B2C2_FLEXCOP_USB is not set +# CONFIG_DVB_TTUSB_BUDGET is not set +# CONFIG_DVB_TTUSB_DEC is not set +# CONFIG_DVB_USB_V2 is not set +CONFIG_EXT4_USE_FOR_EXT2=y +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_WARRIOR is not set +CONFIG_JOYSTICK_XPAD=y +# CONFIG_JOYSTICK_XPAD_FF is not set +# CONFIG_JOYSTICK_XPAD_LEDS is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +# CONFIG_MACH_SONY_LILAC is not set +# CONFIG_MACH_SONY_POPLAR is not set +# CONFIG_MACH_SONY_POPLAR_DSDS is not set +# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MMC_CMD_QUEUE_SIZE=256 +CONFIG_PAGE_COUNTER=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_PSTORE_CONSOLE=y +# CONFIG_PSTORE_PMSG is not set +CONFIG_PSTORE_RAM=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_RCU_BOOST_DELAY=500 +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_MSM_CONSOLE=y +# CONFIG_SMS_USB_DRV is not set +# CONFIG_SONY_FF is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_USB_GL860 is not set +CONFIG_USB_GSPCA=m +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TOUPTEK is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_VIDEO_CLASS is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_VIDEO_AU0828 is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_USBTV is not set diff --git a/arch/arm64/configs/diffconfig/lilac_diffconfig b/arch/arm64/configs/diffconfig/lilac_diffconfig new file mode 100644 index 0000000000000000000000000000000000000000..cf6d5f1b25831f5f283e652e386b4942877fef48 --- /dev/null +++ b/arch/arm64/configs/diffconfig/lilac_diffconfig @@ -0,0 +1,9 @@ +CONFIG_LEDS_QPNP_RGB_SCALE=y +CONFIG_MACH_SONY_LILAC=y +CONFIG_NFC_PN547=y +CONFIG_SENSORS_TCS3490=y +CONFIG_TOF_SENSOR=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_FRONT_CAMERA_LED_SCALE=25 +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y diff --git a/arch/arm64/configs/diffconfig/poplar_diffconfig b/arch/arm64/configs/diffconfig/poplar_diffconfig new file mode 100644 index 0000000000000000000000000000000000000000..9e5bdd136b8fa34837991dc165c7ed6ae5c6c6b4 --- /dev/null +++ b/arch/arm64/configs/diffconfig/poplar_diffconfig @@ -0,0 +1,7 @@ +CONFIG_MACH_SONY_POPLAR=y +CONFIG_NFC_PN547=y +CONFIG_SENSORS_TCS3490=y +CONFIG_TOF_SENSOR=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y diff --git a/arch/arm64/configs/diffconfig/poplar_dsds_diffconfig b/arch/arm64/configs/diffconfig/poplar_dsds_diffconfig new file mode 100644 index 0000000000000000000000000000000000000000..990940fad1844545bf690392c26fa64460851346 --- /dev/null +++ b/arch/arm64/configs/diffconfig/poplar_dsds_diffconfig @@ -0,0 +1,7 @@ +CONFIG_MACH_SONY_POPLAR_DSDS=y +CONFIG_NFC_PN547=y +CONFIG_SENSORS_TCS3490=y +CONFIG_TOF_SENSOR=y +CONFIG_TOUCHSCREEN_CLEARPAD=y +CONFIG_TOUCHSCREEN_CLEARPAD_I2C=y +CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV=y diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index 61418724b897a9048afdd85a20afb38b72a952f3..acde18d2fe31cb64bd9856cbd7a90c6af1254e7d 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -34,7 +34,7 @@ CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index ee2b9fa628ff33db2e87cf93268ca39a4e7a643d..f510f43427ce9df23b05b0e4bcf489935492d253 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -31,7 +31,7 @@ CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index e16fc58ce9138f25ef643c4df43fe73ed16dc7a1..5692f0dcd65ee9791974da1406610e28bc104841 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -16,6 +16,7 @@ CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y @@ -40,7 +41,7 @@ CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -295,7 +296,6 @@ CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=m CONFIG_CLD_LL_CORE=y -CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y CONFIG_KEYBOARD_GPIO=y @@ -321,7 +321,6 @@ CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y -# CONFIG_DEVPORT is not set CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 77157bb85ee1c36814b298e2d574af50dff838f5..993e350ef0004ab6fb0401fa1c43cf2a2f68dd53 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -38,7 +38,7 @@ CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -296,7 +296,6 @@ CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_ATH_CARDS=y CONFIG_WIL6210=m CONFIG_CLD_LL_CORE=y -CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y CONFIG_KEYBOARD_GPIO=y @@ -325,7 +324,6 @@ CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y -# CONFIG_DEVPORT is not set CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig index c7cff4534193d3b2bb725cf15df98134865f6348..b6cb1a4b85746601b4131655cb9386d3379ed0ae 100644 --- a/arch/arm64/configs/sdm660-perf_defconfig +++ b/arch/arm64/configs/sdm660-perf_defconfig @@ -5,9 +5,6 @@ CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y -CONFIG_TASKSTATS=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y @@ -41,7 +38,7 @@ CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -72,7 +69,6 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y -CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y @@ -96,7 +92,6 @@ CONFIG_XFRM_USER=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y -CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y @@ -246,7 +241,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y -CONFIG_UID_SYS_STATS=y CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y @@ -305,7 +299,6 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_STMVL53L0=y # CONFIG_SERIO_SERPORT is not set # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set @@ -316,7 +309,6 @@ CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y -# CONFIG_DEVPORT is not set CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y @@ -582,7 +574,6 @@ CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_AVTIMER=y CONFIG_QCOM_REMOTEQDSS=y CONFIG_MSM_SERVICE_NOTIFIER=y -CONFIG_MSM_QBT1000=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y CONFIG_MSM_RPM_LOG=y CONFIG_MSM_RPM_STATS_LOG=y @@ -616,9 +607,6 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y CONFIG_EXT4_FS_ENCRYPTION=y CONFIG_EXT4_FS_ICE_ENCRYPTION=y -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -651,9 +639,7 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_SOURCE_DUMMY=y CONFIG_PFK=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y -CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_ECHAINIV=y diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig index 0a1b386e2d9fadc1340480dfa857ab9841948214..ccef87ff6a04a04c9b2febb136f0cea3cd5d6fa4 100644 --- a/arch/arm64/configs/sdm660_defconfig +++ b/arch/arm64/configs/sdm660_defconfig @@ -40,7 +40,7 @@ CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -73,7 +73,6 @@ CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y -CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set @@ -97,7 +96,6 @@ CONFIG_XFRM_USER=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y -CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y @@ -310,7 +308,6 @@ CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=y -CONFIG_INPUT_STMVL53L0=y # CONFIG_SERIO_SERPORT is not set # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set @@ -321,7 +318,6 @@ CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y -# CONFIG_DEVPORT is not set CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y @@ -603,7 +599,6 @@ CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_AVTIMER=y CONFIG_QCOM_REMOTEQDSS=y CONFIG_MSM_SERVICE_NOTIFIER=y -CONFIG_MSM_QBT1000=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y CONFIG_MSM_RPM_LOG=y CONFIG_MSM_RPM_STATS_LOG=y @@ -638,9 +633,6 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y CONFIG_EXT4_FS_ENCRYPTION=y CONFIG_EXT4_FS_ICE_ENCRYPTION=y -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -720,9 +712,7 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_SOURCE_DUMMY=y CONFIG_PFK=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y -CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_ECHAINIV=y diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 0a11cd502dbc8ed4875913306a3cb7d167f5136f..aee323b13802ad143e9774d2076a4b1c63731ece 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -22,9 +22,9 @@ #define ACPI_MADT_GICC_LENGTH \ (acpi_gbl_FADT.header.revision < 6 ? 76 : 80) -#define BAD_MADT_GICC_ENTRY(entry, end) \ - (!(entry) || (entry)->header.length != ACPI_MADT_GICC_LENGTH || \ - (unsigned long)(entry) + ACPI_MADT_GICC_LENGTH > (end)) +#define BAD_MADT_GICC_ENTRY(entry, end) \ + (!(entry) || (unsigned long)(entry) + sizeof(*(entry)) > (end) || \ + (entry)->header.length != ACPI_MADT_GICC_LENGTH) /* Basic configuration for ACPI */ #ifdef CONFIG_ACPI diff --git a/arch/arm64/include/asm/bitrev.h b/arch/arm64/include/asm/bitrev.h index a5a0c366013773f980919591c252f0fab5d2ca74..78791d1fea3c8aca314a8cfa7692578e1bb950e2 100644 --- a/arch/arm64/include/asm/bitrev.h +++ b/arch/arm64/include/asm/bitrev.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ #ifndef __ASM_BITREV_H #define __ASM_BITREV_H static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x) diff --git a/arch/arm64/include/asm/crash_notes.h b/arch/arm64/include/asm/crash_notes.h new file mode 100644 index 0000000000000000000000000000000000000000..289fce346a516058e1c9e255bf2531a3e98aaa51 --- /dev/null +++ b/arch/arm64/include/asm/crash_notes.h @@ -0,0 +1,86 @@ +/* arch/arm64/include/asm/crash_notes.h + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __ARM64_CRASH_NOTES_H +#define __ARM64_CRASH_NOTES_H + +#include + +#define PSTATE_NZCV_MASK (PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT) +#define PSTATE_DAIF_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT) + +static inline void crash_notes_save_regs(struct pt_regs *regs) +{ + struct pstate { + u64 nzcv; + u64 daif; + u64 current_el; + u64 sp_sel; + } pstate; + + /* 31 General purpose registers x0-x30 */ + __asm__ __volatile__("str x0, %0" : "=m"(regs->regs[0])); + __asm__ __volatile__("str x1, %0" : "=m"(regs->regs[1])); + __asm__ __volatile__("str x2, %0" : "=m"(regs->regs[2])); + __asm__ __volatile__("str x3, %0" : "=m"(regs->regs[3])); + __asm__ __volatile__("str x4, %0" : "=m"(regs->regs[4])); + __asm__ __volatile__("str x5, %0" : "=m"(regs->regs[5])); + __asm__ __volatile__("str x6, %0" : "=m"(regs->regs[6])); + __asm__ __volatile__("str x7, %0" : "=m"(regs->regs[7])); + __asm__ __volatile__("str x8, %0" : "=m"(regs->regs[8])); + __asm__ __volatile__("str x9, %0" : "=m"(regs->regs[9])); + __asm__ __volatile__("str x10, %0" : "=m"(regs->regs[10])); + __asm__ __volatile__("str x11, %0" : "=m"(regs->regs[11])); + __asm__ __volatile__("str x12, %0" : "=m"(regs->regs[12])); + __asm__ __volatile__("str x13, %0" : "=m"(regs->regs[13])); + __asm__ __volatile__("str x14, %0" : "=m"(regs->regs[14])); + __asm__ __volatile__("str x15, %0" : "=m"(regs->regs[15])); + __asm__ __volatile__("str x16, %0" : "=m"(regs->regs[16])); + __asm__ __volatile__("str x17, %0" : "=m"(regs->regs[17])); + __asm__ __volatile__("str x18, %0" : "=m"(regs->regs[18])); + __asm__ __volatile__("str x19, %0" : "=m"(regs->regs[19])); + __asm__ __volatile__("str x20, %0" : "=m"(regs->regs[20])); + __asm__ __volatile__("str x21, %0" : "=m"(regs->regs[21])); + __asm__ __volatile__("str x22, %0" : "=m"(regs->regs[22])); + __asm__ __volatile__("str x23, %0" : "=m"(regs->regs[23])); + __asm__ __volatile__("str x24, %0" : "=m"(regs->regs[24])); + __asm__ __volatile__("str x25, %0" : "=m"(regs->regs[25])); + __asm__ __volatile__("str x26, %0" : "=m"(regs->regs[26])); + __asm__ __volatile__("str x27, %0" : "=m"(regs->regs[27])); + __asm__ __volatile__("str x28, %0" : "=m"(regs->regs[28])); + __asm__ __volatile__("str x29, %0" : "=m"(regs->regs[29])); + __asm__ __volatile__("str x30, %0" : "=m"(regs->regs[30])); + + /* Save program counter & stack pointer here */ + __asm__ __volatile__( + "mov %[_ARM_sp], sp\n\t" + "adr %[_ARM_pc], 1f\n\t" + "1:" + : [_ARM_pc] "=r" (regs->pc), + [_ARM_sp] "=r" (regs->sp) + ); + + /* Obtain pstate through system registers */ + __asm__ __volatile__("mrs %0, nzcv" : "=&r"(pstate.nzcv)); + __asm__ __volatile__("mrs %0, daif" : "=&r"(pstate.daif)); + __asm__ __volatile__("mrs %0, currentel" : "=&r"(pstate.current_el)); + __asm__ __volatile__("mrs %0, spsel" : "=&r"(pstate.sp_sel)); + regs->pstate = pstate.nzcv & PSTATE_NZCV_MASK; + regs->pstate |= pstate.daif & PSTATE_DAIF_MASK; + regs->pstate |= pstate.current_el & PSR_MODE_MASK; + regs->pstate |= pstate.sp_sel & 1; +} + +#endif diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index b98332269462a830eab9979e07cc9f359b8194fa..a383c288ef490a0d2bbb3199e53496ab2b9b6ce5 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -114,11 +114,12 @@ #define ELF_EXEC_PAGESIZE PAGE_SIZE /* - * This is the base location for PIE (ET_DYN with INTERP) loads. On - * 64-bit, this is raised to 4GB to leave the entire 32-bit address - * space open for things that want to use the area for 32-bit pointers. + * This is the location that an ET_DYN program is loaded if exec'ed. Typical + * use of this is to invoke "./ld.so someprog" to test out a new version of + * the loader. We need to make sure that it is out of the way of the program + * that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE 0x100000000UL +#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) #ifndef __ASSEMBLY__ @@ -169,8 +170,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, #ifdef CONFIG_COMPAT -/* PIE load location for compat arm. Must match ARM ELF_ET_DYN_BASE. */ -#define COMPAT_ELF_ET_DYN_BASE 0x000400000UL +#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3) /* AArch32 registers. */ #define COMPAT_ELF_NGREG 18 diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 3112c2a9d96fbc9574b27cdc084735e3bb35df96..39d613d8a57621bdc4bdf021bfe95c63172f98af 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -16,6 +16,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __ASM_IO_H #define __ASM_IO_H diff --git a/arch/arm64/kernel/perf_trace_counters.c b/arch/arm64/kernel/perf_trace_counters.c index dc92b29ac103cf91b7a8070291b38ddc9467be7a..748ad449fc1899bdbe3dc5a525ff659cb3a0b934 100644 --- a/arch/arm64/kernel/perf_trace_counters.c +++ b/arch/arm64/kernel/perf_trace_counters.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved. +/* 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 @@ -124,7 +124,6 @@ static ssize_t write_enabled_perftp_file_bool(struct file *file, char buf[32]; size_t buf_size; - buf[0] = 0; buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index fc0a7aa2ca82452d8d3440c69a31529947668ba8..c75a672cdda8520ac59c881e79dfe571681a86ab 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -17,6 +17,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include @@ -31,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +67,34 @@ unsigned long __stack_chk_guard __read_mostly; EXPORT_SYMBOL(__stack_chk_guard); #endif +#ifdef CONFIG_ARM64_FLUSH_CONSOLE_ON_RESTART +void arm_machine_flush_console(void) +{ + printk("\n"); + pr_emerg("Restarting %s\n", linux_banner); + if (console_trylock()) { + console_unlock(); + return; + } + + mdelay(50); + + local_irq_disable(); + if (!console_trylock()) + pr_emerg("arm_restart: Console was locked! Busting\n"); + else + pr_emerg("arm_restart: Console was locked!\n"); + if (is_console_suspended()) + resume_console(); + else + console_unlock(); +} +#else +void arm_machine_flush_console(void) +{ +} +#endif + /* * Function pointers to optional machine specific functions */ @@ -163,6 +197,10 @@ void machine_restart(char *cmd) if (efi_enabled(EFI_RUNTIME_SERVICES)) efi_reboot(reboot_mode, NULL); + /* Flush the console to make sure all the relevant messages make it + * out to the console drivers */ + arm_machine_flush_console(); + /* Now call the architecture specific reboot code. */ if (arm_pm_restart) arm_pm_restart(reboot_mode, cmd); @@ -397,7 +435,7 @@ void uao_thread_switch(struct task_struct *next) /* * Thread switching. */ -struct task_struct *__switch_to(struct task_struct *prev, +__notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next) { struct task_struct *last; diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index d031a85e0bc75da694ed345f7fbbd4315518dc46..a3a6b2ea9b4da29c8e4f1fa6f862bc3ea21bc1a6 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -54,7 +54,6 @@ #include #include #include -#include #define CREATE_TRACE_POINTS #include @@ -741,7 +740,6 @@ static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs) pr_crit("CPU%u: stopping\n", cpu); show_regs(regs); dump_stack(); - dump_stack_minidump(regs->sp); arm64_check_cache_ecc(NULL); raw_spin_unlock(&stop_lock); } diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S index 4c1e700840b6ced5a0b2f868bfb4f37dddc8abc0..2534533ceb1d7374b5abfbf70bc3e7c5cce7300e 100644 --- a/arch/arm64/lib/copy_page.S +++ b/arch/arm64/lib/copy_page.S @@ -18,8 +18,6 @@ #include #include #include -#include -#include /* * Copy a page from src to dest (both are page aligned) @@ -29,15 +27,6 @@ * x1 - src */ ENTRY(copy_page) -alternative_if_not ARM64_HAS_NO_HW_PREFETCH - nop - nop -alternative_else - # Prefetch two cache lines ahead. - prfm pldl1strm, [x1, #128] - prfm pldl1strm, [x1, #256] -alternative_endif - ldp x2, x3, [x1] ldp x4, x5, [x1, #16] ldp x6, x7, [x1, #32] @@ -52,12 +41,6 @@ alternative_endif 1: subs x18, x18, #128 -alternative_if_not ARM64_HAS_NO_HW_PREFETCH - nop -alternative_else - prfm pldl1strm, [x1, #384] -alternative_endif - stnp x2, x3, [x0] ldp x2, x3, [x1] stnp x4, x5, [x0, #16] diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index b4ef9ea679a12341ec2b0eead55c5898d3ec8415..8b3812f0a210d725c1e16cfc5355a04f24f64ea2 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -16,6 +16,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c index 8ae4067a5eda2464d22ce5be57ea7e6e572654de..3cedd1f95e0f0897cf3c1d47b6c27cb9182c4003 100644 --- a/arch/mips/ath79/common.c +++ b/arch/mips/ath79/common.c @@ -76,14 +76,14 @@ void ath79_ddr_set_pci_windows(void) { BUG_ON(!ath79_ddr_pci_win_base); - __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0x0); - __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 0x4); - __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 0x8); - __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 0xc); - __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 0x10); - __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 0x14); - __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 0x18); - __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 0x1c); + __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0); + __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 1); + __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 2); + __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 3); + __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 4); + __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 5); + __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 6); + __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 7); } EXPORT_SYMBOL_GPL(ath79_ddr_set_pci_windows); diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index db07793f7b43c1e350403ad135733d70465a6c7e..7791840cf22c0f7c058d32f3abb722eb132f90f8 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -138,7 +137,6 @@ work_pending: andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS beqz t0, work_notifysig work_resched: - TRACE_IRQS_OFF jal schedule local_irq_disable # make sure need_resched and @@ -175,7 +173,6 @@ syscall_exit_work: beqz t0, work_pending # trace bit set? local_irq_enable # could let syscall_trace_leave() # call schedule() instead - TRACE_IRQS_ON move a0, sp jal syscall_trace_leave b resume_userspace diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 0b3e58a3189f48f7432e8d67e9f2e29c5f0f2b6e..f63a289977cc5f34d5ee52daf61f1065153166a1 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -55,6 +55,7 @@ DECLARE_BITMAP(state_support, CPS_PM_STATE_COUNT); * state. Actually per-core rather than per-CPU. */ static DEFINE_PER_CPU_ALIGNED(u32*, ready_count); +static DEFINE_PER_CPU_ALIGNED(void*, ready_count_alloc); /* Indicates online CPUs coupled with the current CPU */ static DEFINE_PER_CPU_ALIGNED(cpumask_t, online_coupled); @@ -624,6 +625,7 @@ static int __init cps_gen_core_entries(unsigned cpu) { enum cps_pm_state state; unsigned core = cpu_data[cpu].core; + unsigned dlinesz = cpu_data[cpu].dcache.linesz; void *entry_fn, *core_rc; for (state = CPS_PM_NC_WAIT; state < CPS_PM_STATE_COUNT; state++) { @@ -643,11 +645,16 @@ static int __init cps_gen_core_entries(unsigned cpu) } if (!per_cpu(ready_count, core)) { - core_rc = kmalloc(sizeof(u32), GFP_KERNEL); + core_rc = kmalloc(dlinesz * 2, GFP_KERNEL); if (!core_rc) { pr_err("Failed allocate core %u ready_count\n", core); return -ENOMEM; } + per_cpu(ready_count_alloc, core) = core_rc; + + /* Ensure ready_count is aligned to a cacheline boundary */ + core_rc += dlinesz - 1; + core_rc = (void *)((unsigned long)core_rc & ~(dlinesz - 1)); per_cpu(ready_count, core) = core_rc; } diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 31ca2edd7218f089fd3fbef742b7625e9ccd83bc..99a402231f4d6ed694392151786a2678e1cb27eb 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -194,8 +194,6 @@ void show_stack(struct task_struct *task, unsigned long *sp) { struct pt_regs regs; mm_segment_t old_fs = get_fs(); - - regs.cp0_status = KSU_KERNEL; if (sp) { regs.regs[29] = (unsigned long)sp; regs.regs[31] = 0; diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index 48d6349fd9d76903f4989dd7478acd2b162259ec..dfb04fcedb042d9b80621ac3197886a1ea3bccda 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -107,31 +107,31 @@ static struct rt2880_pmx_group mt7620a_pinmux_data[] = { }; static struct rt2880_pmx_func pwm1_grp_mt7628[] = { - FUNC("sdxc d6", 3, 19, 1), + FUNC("sdcx", 3, 19, 1), FUNC("utif", 2, 19, 1), FUNC("gpio", 1, 19, 1), - FUNC("pwm1", 0, 19, 1), + FUNC("pwm", 0, 19, 1), }; static struct rt2880_pmx_func pwm0_grp_mt7628[] = { - FUNC("sdxc d7", 3, 18, 1), + FUNC("sdcx", 3, 18, 1), FUNC("utif", 2, 18, 1), FUNC("gpio", 1, 18, 1), - FUNC("pwm0", 0, 18, 1), + FUNC("pwm", 0, 18, 1), }; static struct rt2880_pmx_func uart2_grp_mt7628[] = { - FUNC("sdxc d5 d4", 3, 20, 2), + FUNC("sdcx", 3, 20, 2), FUNC("pwm", 2, 20, 2), FUNC("gpio", 1, 20, 2), - FUNC("uart2", 0, 20, 2), + FUNC("uart", 0, 20, 2), }; static struct rt2880_pmx_func uart1_grp_mt7628[] = { - FUNC("sw_r", 3, 45, 2), + FUNC("sdcx", 3, 45, 2), FUNC("pwm", 2, 45, 2), FUNC("gpio", 1, 45, 2), - FUNC("uart1", 0, 45, 2), + FUNC("uart", 0, 45, 2), }; static struct rt2880_pmx_func i2c_grp_mt7628[] = { @@ -143,21 +143,21 @@ static struct rt2880_pmx_func i2c_grp_mt7628[] = { static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("reclk", 0, 36, 1) }; static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 37, 1) }; -static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 38, 1) }; +static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 15, 38) }; static struct rt2880_pmx_func spi_grp_mt7628[] = { FUNC("spi", 0, 7, 4) }; static struct rt2880_pmx_func sd_mode_grp_mt7628[] = { FUNC("jtag", 3, 22, 8), FUNC("utif", 2, 22, 8), FUNC("gpio", 1, 22, 8), - FUNC("sdxc", 0, 22, 8), + FUNC("sdcx", 0, 22, 8), }; static struct rt2880_pmx_func uart0_grp_mt7628[] = { FUNC("-", 3, 12, 2), FUNC("-", 2, 12, 2), FUNC("gpio", 1, 12, 2), - FUNC("uart0", 0, 12, 2), + FUNC("uart", 0, 12, 2), }; static struct rt2880_pmx_func i2s_grp_mt7628[] = { @@ -171,7 +171,7 @@ static struct rt2880_pmx_func spi_cs1_grp_mt7628[] = { FUNC("-", 3, 6, 1), FUNC("refclk", 2, 6, 1), FUNC("gpio", 1, 6, 1), - FUNC("spi cs1", 0, 6, 1), + FUNC("spi", 0, 6, 1), }; static struct rt2880_pmx_func spis_grp_mt7628[] = { @@ -188,44 +188,28 @@ static struct rt2880_pmx_func gpio_grp_mt7628[] = { FUNC("gpio", 0, 11, 1), }; -static struct rt2880_pmx_func wled_kn_grp_mt7628[] = { - FUNC("rsvd", 3, 35, 1), - FUNC("rsvd", 2, 35, 1), - FUNC("gpio", 1, 35, 1), - FUNC("wled_kn", 0, 35, 1), -}; - -static struct rt2880_pmx_func wled_an_grp_mt7628[] = { - FUNC("rsvd", 3, 44, 1), - FUNC("rsvd", 2, 44, 1), - FUNC("gpio", 1, 44, 1), - FUNC("wled_an", 0, 44, 1), -}; - -#define MT7628_GPIO_MODE_MASK 0x3 - -#define MT7628_GPIO_MODE_WLED_KN 48 -#define MT7628_GPIO_MODE_WLED_AN 32 -#define MT7628_GPIO_MODE_PWM1 30 -#define MT7628_GPIO_MODE_PWM0 28 -#define MT7628_GPIO_MODE_UART2 26 -#define MT7628_GPIO_MODE_UART1 24 -#define MT7628_GPIO_MODE_I2C 20 -#define MT7628_GPIO_MODE_REFCLK 18 -#define MT7628_GPIO_MODE_PERST 16 -#define MT7628_GPIO_MODE_WDT 14 -#define MT7628_GPIO_MODE_SPI 12 -#define MT7628_GPIO_MODE_SDMODE 10 -#define MT7628_GPIO_MODE_UART0 8 -#define MT7628_GPIO_MODE_I2S 6 -#define MT7628_GPIO_MODE_CS1 4 -#define MT7628_GPIO_MODE_SPIS 2 -#define MT7628_GPIO_MODE_GPIO 0 +#define MT7628_GPIO_MODE_MASK 0x3 + +#define MT7628_GPIO_MODE_PWM1 30 +#define MT7628_GPIO_MODE_PWM0 28 +#define MT7628_GPIO_MODE_UART2 26 +#define MT7628_GPIO_MODE_UART1 24 +#define MT7628_GPIO_MODE_I2C 20 +#define MT7628_GPIO_MODE_REFCLK 18 +#define MT7628_GPIO_MODE_PERST 16 +#define MT7628_GPIO_MODE_WDT 14 +#define MT7628_GPIO_MODE_SPI 12 +#define MT7628_GPIO_MODE_SDMODE 10 +#define MT7628_GPIO_MODE_UART0 8 +#define MT7628_GPIO_MODE_I2S 6 +#define MT7628_GPIO_MODE_CS1 4 +#define MT7628_GPIO_MODE_SPIS 2 +#define MT7628_GPIO_MODE_GPIO 0 static struct rt2880_pmx_group mt7628an_pinmux_data[] = { - GRP_G("pwm1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK, + GRP_G("pmw1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_PWM1), - GRP_G("pwm0", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK, + GRP_G("pmw1", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_PWM0), GRP_G("uart2", uart2_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_UART2), @@ -249,10 +233,6 @@ static struct rt2880_pmx_group mt7628an_pinmux_data[] = { 1, MT7628_GPIO_MODE_SPIS), GRP_G("gpio", gpio_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_GPIO), - GRP_G("wled_an", wled_an_grp_mt7628, MT7628_GPIO_MODE_MASK, - 1, MT7628_GPIO_MODE_WLED_AN), - GRP_G("wled_kn", wled_kn_grp_mt7628, MT7628_GPIO_MODE_MASK, - 1, MT7628_GPIO_MODE_WLED_KN), { 0 } }; @@ -459,7 +439,7 @@ void __init ralink_clk_init(void) ralink_clk_add("10000c00.uartlite", periph_rate); ralink_clk_add("10180000.wmac", xtal_rate); - if (IS_ENABLED(CONFIG_USB) && !is_mt76x8()) { + if (IS_ENABLED(CONFIG_USB) && is_mt76x8()) { /* * When the CPU goes into sleep mode, the BUS clock will be * too low for USB to function properly. Adjust the busses diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index 9dd67749c592159767718198c069598c6a3173a8..15506a1ff22a9c87f94058eea9bc22800e8911b2 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -109,5 +109,5 @@ void prom_soc_init(struct ralink_soc_info *soc_info) soc_info->mem_size_max = RT2880_MEM_SIZE_MAX; rt2880_pinmux_data = rt2880_pinmux_data_act; - ralink_soc = RT2880_SOC; + ralink_soc == RT2880_SOC; } diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h index f537252029553d26f870c2b39c0e1a7ba212cb19..d8d60a57183fb32be02adc0eefee76ff97d4aa71 100644 --- a/arch/parisc/include/asm/dma-mapping.h +++ b/arch/parisc/include/asm/dma-mapping.h @@ -39,8 +39,6 @@ struct hppa_dma_ops { ** flush/purge and allocate "regular" cacheable pages for everything. */ -#define DMA_ERROR_CODE (~(dma_addr_t)0) - #ifdef CONFIG_PA11 extern struct hppa_dma_ops pcxl_dma_ops; extern struct hppa_dma_ops pcx_dma_ops; @@ -211,13 +209,12 @@ parisc_walk_tree(struct device *dev) break; } } + BUG_ON(!dev->platform_data); return dev->platform_data; } - -#define GET_IOC(dev) ({ \ - void *__pdata = parisc_walk_tree(dev); \ - __pdata ? HBA_DATA(__pdata)->iommu : NULL; \ -}) + +#define GET_IOC(dev) (HBA_DATA(parisc_walk_tree(dev))->iommu) + #ifdef CONFIG_IOMMU_CCIO struct parisc_device; diff --git a/arch/parisc/include/asm/mmu_context.h b/arch/parisc/include/asm/mmu_context.h index a8122625787846b8ee4233217911b23e7b89e2f6..59be257644335f7fff70b54ca65661633b9eaa22 100644 --- a/arch/parisc/include/asm/mmu_context.h +++ b/arch/parisc/include/asm/mmu_context.h @@ -49,26 +49,15 @@ static inline void load_context(mm_context_t context) mtctl(__space_to_prot(context), 8); } -static inline void switch_mm_irqs_off(struct mm_struct *prev, - struct mm_struct *next, struct task_struct *tsk) +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { + if (prev != next) { mtctl(__pa(next->pgd), 25); load_context(next->context); } } -static inline void switch_mm(struct mm_struct *prev, - struct mm_struct *next, struct task_struct *tsk) -{ - unsigned long flags; - - local_irq_save(flags); - switch_mm_irqs_off(prev, next, tsk); - local_irq_restore(flags); -} -#define switch_mm_irqs_off switch_mm_irqs_off - #define deactivate_mm(tsk,mm) do { } while (0) static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 041e1f9ec1294126d11ca80703c58739ad7c93c1..d4ffcfbc98851e7c3f0707ec9d82470d918bed2e 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -361,7 +361,7 @@ ENTRY_SAME(ni_syscall) /* 263: reserved for vserver */ ENTRY_SAME(add_key) ENTRY_SAME(request_key) /* 265 */ - ENTRY_COMP(keyctl) + ENTRY_SAME(keyctl) ENTRY_SAME(ioprio_set) ENTRY_SAME(ioprio_get) ENTRY_SAME(inotify_init) diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 2f33a67bc531e48299fea9dc4f95e98c91ee35e9..16dbe81c97c9005df3cbb91045ccb6ed20878930 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -298,7 +298,7 @@ bad_area: case 15: /* Data TLB miss fault/Data page fault */ /* send SIGSEGV when outside of vma */ if (!vma || - address < vma->vm_start || address >= vma->vm_end) { + address < vma->vm_start || address > vma->vm_end) { si.si_signo = SIGSEGV; si.si_code = SEGV_MAPERR; break; diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h index 743ad7a400d6c85fc3e50eb59a388d724804131c..ee46ffef608ee1679033a77c8ff5353ba6bfb51c 100644 --- a/arch/powerpc/include/asm/elf.h +++ b/arch/powerpc/include/asm/elf.h @@ -23,13 +23,12 @@ #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE PAGE_SIZE -/* - * This is the base location for PIE (ET_DYN with INTERP) loads. On - * 64-bit, this is raised to 4GB to leave the entire 32-bit address - * space open for things that want to use the area for 32-bit pointers. - */ -#define ELF_ET_DYN_BASE (is_32bit_task() ? 0x000400000UL : \ - 0x100000000UL) +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE 0x20000000 #define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0) diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 6696c19868440cd034d87e9bbc0e2e0bd6bca0aa..98949b0df00a531e2003eef868e05f294600f6df 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -304,17 +304,9 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity) * * For pHyp, we have to enable IO for log retrieval. Otherwise, * 0xFF's is always returned from PCI config space. - * - * When the @severity is EEH_LOG_PERM, the PE is going to be - * removed. Prior to that, the drivers for devices included in - * the PE will be closed. The drivers rely on working IO path - * to bring the devices to quiet state. Otherwise, PCI traffic - * from those devices after they are removed is like to cause - * another unexpected EEH error. */ if (!(pe->type & EEH_PE_PHB)) { - if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG) || - severity == EEH_LOG_PERM) + if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG)) eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); /* diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 1138fec3dd658a6f0702efd9cb0b9b6b97d53cd1..7c053f28140663a4bb092c872a6c88e557fdff9d 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -514,15 +514,6 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) #endif #endif - /* - * jprobes use jprobe_return() which skips the normal return - * path of the function, and this messes up the accounting of the - * function graph tracer. - * - * Pause function graph tracing while performing the jprobe function. - */ - pause_graph_tracing(); - return 1; } @@ -545,8 +536,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) * saved regs... */ memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs)); - /* It's OK to start function graph tracing again */ - unpause_graph_tracing(); preempt_enable_no_resched(); return 1; } diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 396dc44e783b367b19951c195c3e718cf0c86a6a..3c3a367b6e59d609d63880f87eab399be749f371 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -2693,27 +2693,6 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu) return -EINVAL; } - /* - * Don't allow entry with a suspended transaction, because - * the guest entry/exit code will lose it. - * If the guest has TM enabled, save away their TM-related SPRs - * (they will get restored by the TM unavailable interrupt). - */ -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (cpu_has_feature(CPU_FTR_TM) && current->thread.regs && - (current->thread.regs->msr & MSR_TM)) { - if (MSR_TM_ACTIVE(current->thread.regs->msr)) { - run->exit_reason = KVM_EXIT_FAIL_ENTRY; - run->fail_entry.hardware_entry_failure_reason = 0; - return -EINVAL; - } - current->thread.tm_tfhar = mfspr(SPRN_TFHAR); - current->thread.tm_tfiar = mfspr(SPRN_TFIAR); - current->thread.tm_texasr = mfspr(SPRN_TEXASR); - current->thread.regs->msr &= ~MSR_TM; - } -#endif - kvmppc_core_prepare_to_enter(vcpu); /* No need to go into the guest when all we'll do is come back out */ diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index 0b48ce40d3511773db5db3ebe3e8f62b92b8e3f2..4c48b487698cf4208618647d8038cc1a9d72e3aa 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -179,16 +179,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) b slb_finish_load 8: /* invalid EA */ - /* - * It's possible the bad EA is too large to fit in the SLB cache, which - * would mean we'd fail to invalidate it on context switch. So mark the - * SLB cache as full so we force a full flush. We also set cr7+eq to - * mark the address as a kernel address, so slb_finish_load() skips - * trying to insert it into the SLB cache. - */ - li r9,SLB_CACHE_ENTRIES + 1 - sth r9,PACASLBCACHEPTR(r13) - crset 4*cr7+eq li r10,0 /* BAD_VSID */ li r9,0 /* BAD_VSID */ li r11,SLB_VSID_USER /* flags don't much matter */ diff --git a/arch/s390/include/asm/ctl_reg.h b/arch/s390/include/asm/ctl_reg.h index 8e136b88cdf4f13460b960f8db9d02e1ae88324f..d7697ab802f6c94813a27394baa255fa26a93ddc 100644 --- a/arch/s390/include/asm/ctl_reg.h +++ b/arch/s390/include/asm/ctl_reg.h @@ -15,9 +15,7 @@ BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\ asm volatile( \ " lctlg %1,%2,%0\n" \ - : \ - : "Q" (*(addrtype *)(&array)), "i" (low), "i" (high) \ - : "memory"); \ + : : "Q" (*(addrtype *)(&array)), "i" (low), "i" (high));\ } #define __ctl_store(array, low, high) { \ diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index b9eb7b1a49d2506f4cd64c8ef0564223eef7327f..bab6739a1154e1fd9827ff8dfb5c152ef52f3930 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -154,13 +154,14 @@ extern unsigned int vdso_enabled; #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE 4096 -/* - * This is the base location for PIE (ET_DYN with INTERP) loads. On - * 64-bit, this is raised to 4GB to leave the entire 32-bit address - * space open for things that want to use the area for 32-bit pointers. - */ -#define ELF_ET_DYN_BASE (is_compat_task() ? 0x000400000UL : \ - 0x100000000UL) +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. 64-bit + tasks are aligned to 4GB. */ +#define ELF_ET_DYN_BASE (is_32bit_task() ? \ + (STACK_TOP / 3 * 2) : \ + (STACK_TOP / 3 * 2) & ~((1UL << 32) - 1)) /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. */ diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c index 7de207a11014a4054b81fe02fd069db102c491d7..dd14616b773970d13c2886f255c0f76b4eb58450 100644 --- a/arch/x86/crypto/sha1_ssse3_glue.c +++ b/arch/x86/crypto/sha1_ssse3_glue.c @@ -201,7 +201,7 @@ asmlinkage void sha1_transform_avx2(u32 *digest, const char *data, static bool avx2_usable(void) { - if (false && avx_usable() && boot_cpu_has(X86_FEATURE_AVX2) + if (avx_usable() && boot_cpu_has(X86_FEATURE_AVX2) && boot_cpu_has(X86_FEATURE_BMI1) && boot_cpu_has(X86_FEATURE_BMI2)) return true; diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 07cf288b692ed42bee86c3026247508b170d87ad..d262f985bbc8436884d1ae55274a6a7aebf6e19b 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -245,13 +245,12 @@ extern int force_personality32; #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE 4096 -/* - * This is the base location for PIE (ET_DYN with INTERP) loads. On - * 64-bit, this is raised to 4GB to leave the entire 32-bit address - * space open for things that want to use the area for 32-bit pointers. - */ -#define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \ - 0x100000000UL) +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index 19d14ac23ef961a0fe7bf8fcdfe953773ab724dc..e9cd7befcb76af6e4052c193b879b5f869420754 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -221,9 +221,6 @@ struct x86_emulate_ops { void (*get_cpuid)(struct x86_emulate_ctxt *ctxt, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx); void (*set_nmi_mask)(struct x86_emulate_ctxt *ctxt, bool masked); - - unsigned (*get_hflags)(struct x86_emulate_ctxt *ctxt); - void (*set_hflags)(struct x86_emulate_ctxt *ctxt, unsigned hflags); }; typedef u32 __attribute__((vector_size(16))) sse128_t; @@ -293,6 +290,7 @@ struct x86_emulate_ctxt { /* interruptibility state, as a result of execution of STI or MOV SS */ int interruptibility; + int emul_flags; bool perm_ok; /* do not check permissions if true */ bool ud; /* inject an #UD if host doesn't support insn */ diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 37db36fddc88628d1f2218dd5ddc0ecd57ed6846..690b4027e17c994fdef4a626f270ca8b97ee041a 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -405,8 +405,6 @@ #define MSR_IA32_TSC_ADJUST 0x0000003b #define MSR_IA32_BNDCFGS 0x00000d90 -#define MSR_IA32_BNDCFGS_RSVD 0x00000ffc - #define MSR_IA32_XSS 0x00000da0 #define FEATURE_CONTROL_LOCKED (1<<0) diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h index fffb2794dd895521d4f6ca39a5de4c2544c1a676..0b1ff4c1c14e782c0375027ce99cab09e96a04fb 100644 --- a/arch/x86/include/asm/pat.h +++ b/arch/x86/include/asm/pat.h @@ -7,7 +7,6 @@ bool pat_enabled(void); void pat_disable(const char *reason); extern void pat_init(void); -extern void init_cache_modes(void); extern int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index e67b834279b24f7cae35da690660b201f5014130..d2bbe343fda74a87307675b3a65704e2cc96769b 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1048,13 +1048,6 @@ void __init setup_arch(char **cmdline_p) if (mtrr_trim_uncached_memory(max_pfn)) max_pfn = e820_end_of_ram_pfn(); - /* - * This call is required when the CPU does not support PAT. If - * mtrr_bp_init() invoked it already via pat_init() the call has no - * effect. - */ - init_cache_modes(); - #ifdef CONFIG_X86_32 /* max_low_pfn get updated here */ find_low_pfn_range(); diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 83d6369c45f59fc6cfb2527266faa80f9427423d..9357b29de9bcc19d18c7cdadf2e48e9900072ed3 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -46,18 +46,11 @@ static u32 xstate_required_size(u64 xstate_bv, bool compacted) return ret; } -bool kvm_mpx_supported(void) -{ - return ((host_xcr0 & (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR)) - && kvm_x86_ops->mpx_supported()); -} -EXPORT_SYMBOL_GPL(kvm_mpx_supported); - u64 kvm_supported_xcr0(void) { u64 xcr0 = KVM_SUPPORTED_XCR0 & host_xcr0; - if (!kvm_mpx_supported()) + if (!kvm_x86_ops->mpx_supported()) xcr0 &= ~(XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); return xcr0; @@ -104,7 +97,7 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu) if (best && (best->eax & (F(XSAVES) | F(XSAVEC)))) best->ebx = xstate_required_size(vcpu->arch.xcr0, true); - vcpu->arch.eager_fpu = use_eager_fpu(); + vcpu->arch.eager_fpu = use_eager_fpu() || guest_cpuid_has_mpx(vcpu); if (vcpu->arch.eager_fpu) kvm_x86_ops->fpu_activate(vcpu); @@ -302,7 +295,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, #endif unsigned f_rdtscp = kvm_x86_ops->rdtscp_supported() ? F(RDTSCP) : 0; unsigned f_invpcid = kvm_x86_ops->invpcid_supported() ? F(INVPCID) : 0; - unsigned f_mpx = kvm_mpx_supported() ? F(MPX) : 0; + unsigned f_mpx = kvm_x86_ops->mpx_supported() ? F(MPX) : 0; unsigned f_xsaves = kvm_x86_ops->xsaves_supported() ? F(XSAVES) : 0; /* cpuid 1.edx */ diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index d1534feefcfeb44990c0cfe66da008cb41a34731..3f5c48ddba453064ff6dbe91731d1d0c7776be53 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -4,7 +4,6 @@ #include "x86.h" int kvm_update_cpuid(struct kvm_vcpu *vcpu); -bool kvm_mpx_supported(void); struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, u32 function, u32 index); int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid, @@ -135,20 +134,20 @@ static inline bool guest_cpuid_has_rtm(struct kvm_vcpu *vcpu) return best && (best->ebx & bit(X86_FEATURE_RTM)); } -static inline bool guest_cpuid_has_pcommit(struct kvm_vcpu *vcpu) +static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; best = kvm_find_cpuid_entry(vcpu, 7, 0); - return best && (best->ebx & bit(X86_FEATURE_PCOMMIT)); + return best && (best->ebx & bit(X86_FEATURE_MPX)); } -static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu) +static inline bool guest_cpuid_has_pcommit(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; best = kvm_find_cpuid_entry(vcpu, 7, 0); - return best && (best->ebx & bit(X86_FEATURE_MPX)); + return best && (best->ebx & bit(X86_FEATURE_PCOMMIT)); } static inline bool guest_cpuid_has_rdtscp(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 04b2f3cad7ba16825de562f4181dc7be81f962e3..1dcea225977db0c0c618428fee648f9cb766f9d4 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2531,7 +2531,7 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt) u64 smbase; int ret; - if ((ctxt->ops->get_hflags(ctxt) & X86EMUL_SMM_MASK) == 0) + if ((ctxt->emul_flags & X86EMUL_SMM_MASK) == 0) return emulate_ud(ctxt); /* @@ -2580,11 +2580,11 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt) return X86EMUL_UNHANDLEABLE; } - if ((ctxt->ops->get_hflags(ctxt) & X86EMUL_SMM_INSIDE_NMI_MASK) == 0) + if ((ctxt->emul_flags & X86EMUL_SMM_INSIDE_NMI_MASK) == 0) ctxt->ops->set_nmi_mask(ctxt, false); - ctxt->ops->set_hflags(ctxt, ctxt->ops->get_hflags(ctxt) & - ~(X86EMUL_SMM_INSIDE_NMI_MASK | X86EMUL_SMM_MASK)); + ctxt->emul_flags &= ~X86EMUL_SMM_INSIDE_NMI_MASK; + ctxt->emul_flags &= ~X86EMUL_SMM_MASK; return X86EMUL_CONTINUE; } @@ -5296,7 +5296,6 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) const struct x86_emulate_ops *ops = ctxt->ops; int rc = X86EMUL_CONTINUE; int saved_dst_type = ctxt->dst.type; - unsigned emul_flags; ctxt->mem_read.pos = 0; @@ -5311,7 +5310,6 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } - emul_flags = ctxt->ops->get_hflags(ctxt); if (unlikely(ctxt->d & (No64|Undefined|Sse|Mmx|Intercept|CheckPerm|Priv|Prot|String))) { if ((ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) || @@ -5345,7 +5343,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) fetch_possible_mmx_operand(ctxt, &ctxt->dst); } - if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && ctxt->intercept) { + if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && ctxt->intercept) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_PRE_EXCEPT); if (rc != X86EMUL_CONTINUE) @@ -5374,7 +5372,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } - if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { + if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_POST_EXCEPT); if (rc != X86EMUL_CONTINUE) @@ -5428,7 +5426,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) special_insn: - if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { + if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_POST_MEMACCESS); if (rc != X86EMUL_CONTINUE) diff --git a/arch/x86/kvm/pmu_intel.c b/arch/x86/kvm/pmu_intel.c index 23a7c7ba377aaf4fdc198c16004177438f5e0912..ab38af4f4947f6a9cb648b37dfe032a612b048f1 100644 --- a/arch/x86/kvm/pmu_intel.c +++ b/arch/x86/kvm/pmu_intel.c @@ -294,7 +294,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) ((u64)1 << edx.split.bit_width_fixed) - 1; } - pmu->global_ctrl = ((1ull << pmu->nr_arch_gp_counters) - 1) | + pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) | (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED); pmu->global_ctrl_mask = ~pmu->global_ctrl; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index b12391119ce870f504d74aed14573c031b722e11..50ca8f409a7ce692e6a09afb09f85f3b774bbe95 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -863,6 +863,7 @@ static unsigned long nested_ept_get_cr3(struct kvm_vcpu *vcpu); static u64 construct_eptp(unsigned long root_hpa); static void kvm_cpu_vmxon(u64 addr); static void kvm_cpu_vmxoff(void); +static bool vmx_mpx_supported(void); static bool vmx_xsaves_supported(void); static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu); static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr); @@ -2263,7 +2264,7 @@ static int nested_vmx_check_exception(struct kvm_vcpu *vcpu, unsigned nr) if (!(vmcs12->exception_bitmap & (1u << nr))) return 0; - nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI, + nested_vmx_vmexit(vcpu, to_vmx(vcpu)->exit_reason, vmcs_read32(VM_EXIT_INTR_INFO), vmcs_readl(EXIT_QUALIFICATION)); return 1; @@ -2540,7 +2541,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx) VM_EXIT_LOAD_IA32_EFER | VM_EXIT_SAVE_IA32_EFER | VM_EXIT_SAVE_VMX_PREEMPTION_TIMER | VM_EXIT_ACK_INTR_ON_EXIT; - if (kvm_mpx_supported()) + if (vmx_mpx_supported()) vmx->nested.nested_vmx_exit_ctls_high |= VM_EXIT_CLEAR_BNDCFGS; /* We support free control of debug control saving. */ @@ -2561,7 +2562,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx) VM_ENTRY_LOAD_IA32_PAT; vmx->nested.nested_vmx_entry_ctls_high |= (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | VM_ENTRY_LOAD_IA32_EFER); - if (kvm_mpx_supported()) + if (vmx_mpx_supported()) vmx->nested.nested_vmx_entry_ctls_high |= VM_ENTRY_LOAD_BNDCFGS; /* We support free control of debug control loading. */ @@ -2812,8 +2813,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = vmcs_readl(GUEST_SYSENTER_ESP); break; case MSR_IA32_BNDCFGS: - if (!kvm_mpx_supported() || - (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu))) + if (!vmx_mpx_supported()) return 1; msr_info->data = vmcs_read64(GUEST_BNDCFGS); break; @@ -2890,11 +2890,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vmcs_writel(GUEST_SYSENTER_ESP, data); break; case MSR_IA32_BNDCFGS: - if (!kvm_mpx_supported() || - (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu))) - return 1; - if (is_noncanonical_address(data & PAGE_MASK) || - (data & MSR_IA32_BNDCFGS_RSVD)) + if (!vmx_mpx_supported()) return 1; vmcs_write64(GUEST_BNDCFGS, data); break; @@ -3367,7 +3363,7 @@ static void init_vmcs_shadow_fields(void) for (i = j = 0; i < max_shadow_read_write_fields; i++) { switch (shadow_read_write_fields[i]) { case GUEST_BNDCFGS: - if (!kvm_mpx_supported()) + if (!vmx_mpx_supported()) continue; break; default: @@ -6257,6 +6253,7 @@ static __init int hardware_setup(void) vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false); vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false); vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false); + vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true); memcpy(vmx_msr_bitmap_legacy_x2apic, vmx_msr_bitmap_legacy, PAGE_SIZE); @@ -10268,7 +10265,7 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vmcs12->guest_sysenter_cs = vmcs_read32(GUEST_SYSENTER_CS); vmcs12->guest_sysenter_esp = vmcs_readl(GUEST_SYSENTER_ESP); vmcs12->guest_sysenter_eip = vmcs_readl(GUEST_SYSENTER_EIP); - if (kvm_mpx_supported()) + if (vmx_mpx_supported()) vmcs12->guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS); if (nested_cpu_has_xsaves(vmcs12)) vmcs12->xss_exit_bitmap = vmcs_read64(XSS_EXIT_BITMAP); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8e526c6fd784f72c2731d528b1c7cae9c2aca1e9..6c82792487e9bfbecaf5d0569159e0b38220640f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4844,8 +4844,6 @@ static bool emulator_get_segment(struct x86_emulate_ctxt *ctxt, u16 *selector, if (var.unusable) { memset(desc, 0, sizeof(*desc)); - if (base3) - *base3 = 0; return false; } @@ -5001,16 +4999,6 @@ static void emulator_set_nmi_mask(struct x86_emulate_ctxt *ctxt, bool masked) kvm_x86_ops->set_nmi_mask(emul_to_vcpu(ctxt), masked); } -static unsigned emulator_get_hflags(struct x86_emulate_ctxt *ctxt) -{ - return emul_to_vcpu(ctxt)->arch.hflags; -} - -static void emulator_set_hflags(struct x86_emulate_ctxt *ctxt, unsigned emul_flags) -{ - kvm_set_hflags(emul_to_vcpu(ctxt), emul_flags); -} - static const struct x86_emulate_ops emulate_ops = { .read_gpr = emulator_read_gpr, .write_gpr = emulator_write_gpr, @@ -5050,8 +5038,6 @@ static const struct x86_emulate_ops emulate_ops = { .intercept = emulator_intercept, .get_cpuid = emulator_get_cpuid, .set_nmi_mask = emulator_set_nmi_mask, - .get_hflags = emulator_get_hflags, - .set_hflags = emulator_set_hflags, }; static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) @@ -5104,6 +5090,7 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) BUILD_BUG_ON(HF_GUEST_MASK != X86EMUL_GUEST_MASK); BUILD_BUG_ON(HF_SMM_MASK != X86EMUL_SMM_MASK); BUILD_BUG_ON(HF_SMM_INSIDE_NMI_MASK != X86EMUL_SMM_INSIDE_NMI_MASK); + ctxt->emul_flags = vcpu->arch.hflags; init_decode_cache(ctxt); vcpu->arch.emulate_regs_need_sync_from_vcpu = false; @@ -5499,6 +5486,8 @@ restart: unsigned long rflags = kvm_x86_ops->get_rflags(vcpu); toggle_interruptibility(vcpu, ctxt->interruptibility); vcpu->arch.emulate_regs_need_sync_to_vcpu = false; + if (vcpu->arch.hflags != ctxt->emul_flags) + kvm_set_hflags(vcpu, ctxt->emul_flags); kvm_rip_write(vcpu, ctxt->eip); if (r == EMULATE_DONE) kvm_vcpu_check_singlestep(vcpu, rflags, &r); @@ -5985,8 +5974,7 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt) kvm_x86_ops->patch_hypercall(vcpu, instruction); - return emulator_write_emulated(ctxt, rip, instruction, 3, - &ctxt->exception); + return emulator_write_emulated(ctxt, rip, instruction, 3, NULL); } static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu) diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index 423644c230e76eac07c1b57bd62772cdb9b0c503..27f89c79a44b7da6fc6aef54e3961426e542e7ed 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -80,7 +80,7 @@ ENTRY(copy_user_generic_unrolled) movl %edx,%ecx andl $63,%edx shrl $6,%ecx - jz .L_copy_short_string + jz 17f 1: movq (%rsi),%r8 2: movq 1*8(%rsi),%r9 3: movq 2*8(%rsi),%r10 @@ -101,8 +101,7 @@ ENTRY(copy_user_generic_unrolled) leaq 64(%rdi),%rdi decl %ecx jnz 1b -.L_copy_short_string: - movl %edx,%ecx +17: movl %edx,%ecx andl $7,%edx shrl $3,%ecx jz 20f @@ -216,8 +215,6 @@ ENDPROC(copy_user_generic_string) */ ENTRY(copy_user_enhanced_fast_string) ASM_STAC - cmpl $64,%edx - jb .L_copy_short_string /* less then 64 bytes, avoid the costly 'rep' */ movl %edx,%ecx 1: rep movsb diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index 7ed47b1e6f42d0d96a67484d0ef9c68fd9900195..ef05755a190063cdf79210f7ac164aef1a0f4ec5 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -293,7 +293,7 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs) * We were not able to extract an address from the instruction, * probably because there was something invalid in it. */ - if (info->si_addr == (void __user *)-1) { + if (info->si_addr == (void *)-1) { err = -EINVAL; goto err_out; } @@ -525,7 +525,15 @@ int mpx_handle_bd_fault(void) if (!kernel_managing_mpx_tables(current->mm)) return -EINVAL; - return do_mpx_bt_fault(); + if (do_mpx_bt_fault()) { + force_sig(SIGSEGV, current); + /* + * The force_sig() is essentially "handling" this + * exception, so we do not pass up the error + * from do_mpx_bt_fault(). + */ + } + return 0; } /* diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 3f1bb4f93a5aef406070c34f462276a8263a7ff9..6ad687d104cafb360c26cb1110c8fdf45fa43680 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -36,14 +36,14 @@ #undef pr_fmt #define pr_fmt(fmt) "" fmt -static bool __read_mostly boot_cpu_done; -static bool __read_mostly pat_disabled = !IS_ENABLED(CONFIG_X86_PAT); -static bool __read_mostly pat_initialized; -static bool __read_mostly init_cm_done; +static bool boot_cpu_done; + +static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT); +static void init_cache_modes(void); void pat_disable(const char *reason) { - if (pat_disabled) + if (!__pat_enabled) return; if (boot_cpu_done) { @@ -51,8 +51,10 @@ void pat_disable(const char *reason) return; } - pat_disabled = true; + __pat_enabled = 0; pr_info("x86/PAT: %s\n", reason); + + init_cache_modes(); } static int __init nopat(char *str) @@ -64,7 +66,7 @@ early_param("nopat", nopat); bool pat_enabled(void) { - return pat_initialized; + return !!__pat_enabled; } EXPORT_SYMBOL_GPL(pat_enabled); @@ -202,8 +204,6 @@ static void __init_cache_modes(u64 pat) update_cache_mode_entry(i, cache); } pr_info("x86/PAT: Configuration [0-7]: %s\n", pat_msg); - - init_cm_done = true; } #define PAT(x, y) ((u64)PAT_ ## y << ((x)*8)) @@ -224,7 +224,6 @@ static void pat_bsp_init(u64 pat) } wrmsrl(MSR_IA32_CR_PAT, pat); - pat_initialized = true; __init_cache_modes(pat); } @@ -242,9 +241,10 @@ static void pat_ap_init(u64 pat) wrmsrl(MSR_IA32_CR_PAT, pat); } -void init_cache_modes(void) +static void init_cache_modes(void) { u64 pat = 0; + static int init_cm_done; if (init_cm_done) return; @@ -286,6 +286,8 @@ void init_cache_modes(void) } __init_cache_modes(pat); + + init_cm_done = 1; } /** @@ -303,8 +305,10 @@ void pat_init(void) u64 pat; struct cpuinfo_x86 *c = &boot_cpu_data; - if (pat_disabled) + if (!pat_enabled()) { + init_cache_modes(); return; + } if ((c->x86_vendor == X86_VENDOR_INTEL) && (((c->x86 == 0x6) && (c->x86_model <= 0xd)) || diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 5a760fd66beca445da8a94fd2a4d8840149a9da5..5fb6adaaa7964d68c1bd7cbc81d6c2ed6bd44bcd 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -134,6 +134,8 @@ void native_flush_tlb_others(const struct cpumask *cpumask, { struct flush_tlb_info info; + if (end == 0) + end = start + PAGE_SIZE; info.flush_mm = mm; info.flush_start = start; info.flush_end = end; @@ -262,7 +264,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long start) } if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) - flush_tlb_others(mm_cpumask(mm), mm, start, start + PAGE_SIZE); + flush_tlb_others(mm_cpumask(mm), mm, start, 0UL); preempt_enable(); } diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index 73eb7fd4aec48d02e367b87ec1326da6c4022bde..0c2fae8d929df154ff0324994df5f5341f2d4c52 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -992,12 +992,11 @@ static void emit_relocs(int as_text, int use_real_mode) die("Segment relocations found but --realmode not specified\n"); /* Order the relocations for more efficient processing */ + sort_relocs(&relocs16); sort_relocs(&relocs32); #if ELF_BITS == 64 sort_relocs(&relocs32neg); sort_relocs(&relocs64); -#else - sort_relocs(&relocs16); #endif /* Print the relocations */ diff --git a/drivers/android/Makefile b/drivers/android/Makefile index 4b7c726bb560944c2bfd23e267a051018efffc05..3b7e4b072c58c77dcd1b283711dfa96e34abdaa7 100644 --- a/drivers/android/Makefile +++ b/drivers/android/Makefile @@ -1,3 +1,3 @@ ccflags-y += -I$(src) # needed for trace events -obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o +obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o diff --git a/drivers/android/binder.c b/drivers/android/binder.c index c72b7476b626868f333e0be799db24adab9725fd..f9a1c2ce77fc61f1cd825bfe5a4f5f1efcaeab13 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -14,50 +14,23 @@ * GNU General Public License for more details. * */ - /* - * Locking overview - * - * There are 3 main spinlocks which must be acquired in the - * order shown: - * - * 1) proc->outer_lock : protects binder_ref - * binder_proc_lock() and binder_proc_unlock() are - * used to acq/rel. - * 2) node->lock : protects most fields of binder_node. - * binder_node_lock() and binder_node_unlock() are - * used to acq/rel - * 3) proc->inner_lock : protects the thread and node lists - * (proc->threads, proc->waiting_threads, proc->nodes) - * and all todo lists associated with the binder_proc - * (proc->todo, thread->todo, proc->delivered_death and - * node->async_todo), as well as thread->transaction_stack - * binder_inner_proc_lock() and binder_inner_proc_unlock() - * are used to acq/rel - * - * Any lock under procA must never be nested under any lock at the same - * level or below on procB. - * - * Functions that require a lock held on entry indicate which lock - * in the suffix of the function name: - * - * foo_olocked() : requires node->outer_lock - * foo_nlocked() : requires node->lock - * foo_ilocked() : requires proc->inner_lock - * foo_oilocked(): requires proc->outer_lock and proc->inner_lock - * foo_nilocked(): requires node->lock and proc->inner_lock - * ... + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -67,32 +40,23 @@ #include #include #include +#include +#include #include #include -#include #ifdef CONFIG_ANDROID_BINDER_IPC_32BIT #define BINDER_IPC_32BIT 1 #endif #include -#include "binder_alloc.h" #include "binder_trace.h" -static HLIST_HEAD(binder_deferred_list); -static DEFINE_MUTEX(binder_deferred_lock); - static HLIST_HEAD(binder_devices); -static HLIST_HEAD(binder_procs); -static DEFINE_MUTEX(binder_procs_lock); - -static HLIST_HEAD(binder_dead_nodes); -static DEFINE_SPINLOCK(binder_dead_nodes_lock); static struct dentry *binder_debugfs_dir_entry_root; static struct dentry *binder_debugfs_dir_entry_proc; -static atomic_t binder_last_id; -static struct workqueue_struct *binder_deferred_workqueue; +atomic_t binder_last_id; #define BINDER_DEBUG_ENTRY(name) \ static int binder_##name##_open(struct inode *inode, struct file *file) \ @@ -138,13 +102,17 @@ enum { BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10, BINDER_DEBUG_FREE_BUFFER = 1U << 11, BINDER_DEBUG_INTERNAL_REFS = 1U << 12, - BINDER_DEBUG_PRIORITY_CAP = 1U << 13, - BINDER_DEBUG_SPINLOCKS = 1U << 14, + BINDER_DEBUG_BUFFER_ALLOC = 1U << 13, + BINDER_DEBUG_PRIORITY_CAP = 1U << 14, + BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15, }; static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); +static bool binder_debug_no_lock; +module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO); + static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; module_param_named(devices, binder_devices_param, charp, S_IRUGO); @@ -201,27 +169,30 @@ enum binder_stat_types { }; struct binder_stats { - atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; - atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; + int br[_IOC_NR(BR_FAILED_REPLY) + 1]; + int bc[_IOC_NR(BC_REPLY_SG) + 1]; +}; + +/* These are still global, since it's not always easy to get the context */ +struct binder_obj_stats { atomic_t obj_created[BINDER_STAT_COUNT]; atomic_t obj_deleted[BINDER_STAT_COUNT]; }; -static struct binder_stats binder_stats; +static struct binder_obj_stats binder_obj_stats; static inline void binder_stats_deleted(enum binder_stat_types type) { - atomic_inc(&binder_stats.obj_deleted[type]); + atomic_inc(&binder_obj_stats.obj_deleted[type]); } static inline void binder_stats_created(enum binder_stat_types type) { - atomic_inc(&binder_stats.obj_created[type]); + atomic_inc(&binder_obj_stats.obj_created[type]); } struct binder_transaction_log_entry { int debug_id; - int debug_id_done; int call_type; int from_proc; int from_thread; @@ -231,45 +202,48 @@ struct binder_transaction_log_entry { int to_node; int data_size; int offsets_size; - int return_error_line; - uint32_t return_error; - uint32_t return_error_param; const char *context_name; }; struct binder_transaction_log { - atomic_t cur; - bool full; + int next; + int full; struct binder_transaction_log_entry entry[32]; }; -static struct binder_transaction_log binder_transaction_log; -static struct binder_transaction_log binder_transaction_log_failed; static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) { struct binder_transaction_log_entry *e; - unsigned int cur = atomic_inc_return(&log->cur); - if (cur >= ARRAY_SIZE(log->entry)) - log->full = 1; - e = &log->entry[cur % ARRAY_SIZE(log->entry)]; - WRITE_ONCE(e->debug_id_done, 0); - /* - * write-barrier to synchronize access to e->debug_id_done. - * We make sure the initialized 0 value is seen before - * memset() other fields are zeroed by memset. - */ - smp_wmb(); + e = &log->entry[log->next]; memset(e, 0, sizeof(*e)); + log->next++; + if (log->next == ARRAY_SIZE(log->entry)) { + log->next = 0; + log->full = 1; + } return e; } struct binder_context { struct binder_node *binder_context_mgr_node; - struct mutex context_mgr_node_lock; - kuid_t binder_context_mgr_uid; const char *name; + + struct mutex binder_main_lock; + struct mutex binder_deferred_lock; + struct mutex binder_mmap_lock; + + struct hlist_head binder_procs; + struct hlist_head binder_dead_nodes; + struct hlist_head binder_deferred_list; + + struct work_struct deferred_work; + struct workqueue_struct *binder_deferred_workqueue; + struct binder_transaction_log transaction_log; + struct binder_transaction_log transaction_log_failed; + + struct binder_stats binder_stats; }; struct binder_device { @@ -278,20 +252,11 @@ struct binder_device { struct binder_context context; }; -/** - * struct binder_work - work enqueued on a worklist - * @entry: node enqueued on list - * @type: type of work to be performed - * - * There are separate work lists for proc, thread, and node (async). - */ struct binder_work { struct list_head entry; - enum { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, - BINDER_WORK_RETURN_ERROR, BINDER_WORK_NODE, BINDER_WORK_DEAD_BINDER, BINDER_WORK_DEAD_BINDER_AND_CLEAR, @@ -299,76 +264,8 @@ struct binder_work { } type; }; -struct binder_error { - struct binder_work work; - uint32_t cmd; -}; - -/** - * struct binder_node - binder node bookkeeping - * @debug_id: unique ID for debugging - * (invariant after initialized) - * @lock: lock for node fields - * @work: worklist element for node work - * (protected by @proc->inner_lock) - * @rb_node: element for proc->nodes tree - * (protected by @proc->inner_lock) - * @dead_node: element for binder_dead_nodes list - * (protected by binder_dead_nodes_lock) - * @proc: binder_proc that owns this node - * (invariant after initialized) - * @refs: list of references on this node - * (protected by @lock) - * @internal_strong_refs: used to take strong references when - * initiating a transaction - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @local_weak_refs: weak user refs from local process - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @local_strong_refs: strong user refs from local process - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @tmp_refs: temporary kernel refs - * (protected by @proc->inner_lock while @proc - * is valid, and by binder_dead_nodes_lock - * if @proc is NULL. During inc/dec and node release - * it is also protected by @lock to provide safety - * as the node dies and @proc becomes NULL) - * @ptr: userspace pointer for node - * (invariant, no lock needed) - * @cookie: userspace cookie for node - * (invariant, no lock needed) - * @has_strong_ref: userspace notified of strong ref - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @pending_strong_ref: userspace has acked notification of strong ref - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @has_weak_ref: userspace notified of weak ref - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @pending_weak_ref: userspace has acked notification of weak ref - * (protected by @proc->inner_lock if @proc - * and by @lock) - * @has_async_transaction: async transaction to node in progress - * (protected by @lock) - * @sched_policy: minimum scheduling policy for node - * (invariant after initialized) - * @accept_fds: file descriptor operations supported for node - * (invariant after initialized) - * @min_priority: minimum scheduling priority - * (invariant after initialized) - * @inherit_rt: inherit RT scheduling policy from caller - * (invariant after initialized) - * @async_todo: list of async work items - * (protected by @proc->inner_lock) - * - * Bookkeeping structure for binder nodes. - */ struct binder_node { int debug_id; - spinlock_t lock; struct binder_work work; union { struct rb_node rb_node; @@ -379,185 +276,88 @@ struct binder_node { int internal_strong_refs; int local_weak_refs; int local_strong_refs; - int tmp_refs; binder_uintptr_t ptr; binder_uintptr_t cookie; - struct { - /* - * bitfield elements protected by - * proc inner_lock - */ - u8 has_strong_ref:1; - u8 pending_strong_ref:1; - u8 has_weak_ref:1; - u8 pending_weak_ref:1; - }; - struct { - /* - * invariant after initialization - */ - u8 sched_policy:2; - u8 inherit_rt:1; - u8 accept_fds:1; - u8 min_priority; - }; - bool has_async_transaction; + unsigned has_strong_ref:1; + unsigned pending_strong_ref:1; + unsigned has_weak_ref:1; + unsigned pending_weak_ref:1; + unsigned has_async_transaction:1; + unsigned accept_fds:1; + unsigned min_priority:8; struct list_head async_todo; }; struct binder_ref_death { - /** - * @work: worklist element for death notifications - * (protected by inner_lock of the proc that - * this ref belongs to) - */ struct binder_work work; binder_uintptr_t cookie; }; -/** - * struct binder_ref_data - binder_ref counts and id - * @debug_id: unique ID for the ref - * @desc: unique userspace handle for ref - * @strong: strong ref count (debugging only if not locked) - * @weak: weak ref count (debugging only if not locked) - * - * Structure to hold ref count and ref id information. Since - * the actual ref can only be accessed with a lock, this structure - * is used to return information about the ref to callers of - * ref inc/dec functions. - */ -struct binder_ref_data { - int debug_id; - uint32_t desc; - int strong; - int weak; -}; - -/** - * struct binder_ref - struct to track references on nodes - * @data: binder_ref_data containing id, handle, and current refcounts - * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree - * @rb_node_node: node for lookup by @node in proc's rb_tree - * @node_entry: list entry for node->refs list in target node - * (protected by @node->lock) - * @proc: binder_proc containing ref - * @node: binder_node of target node. When cleaning up a - * ref for deletion in binder_cleanup_ref, a non-NULL - * @node indicates the node must be freed - * @death: pointer to death notification (ref_death) if requested - * (protected by @node->lock) - * - * Structure to track references from procA to target node (on procB). This - * structure is unsafe to access without holding @proc->outer_lock. - */ struct binder_ref { /* Lookups needed: */ /* node + proc => ref (transaction) */ /* desc + proc => ref (transaction, inc/dec ref) */ /* node => refs + procs (proc exit) */ - struct binder_ref_data data; + int debug_id; struct rb_node rb_node_desc; struct rb_node rb_node_node; struct hlist_node node_entry; struct binder_proc *proc; struct binder_node *node; + uint32_t desc; + int strong; + int weak; struct binder_ref_death *death; }; +struct binder_buffer { + struct list_head entry; /* free and allocated entries by address */ + struct rb_node rb_node; /* free entry by size or allocated entry */ + /* by address */ + unsigned free:1; + unsigned allow_user_free:1; + unsigned async_transaction:1; + unsigned debug_id:29; + + struct binder_transaction *transaction; + + struct binder_node *target_node; + size_t data_size; + size_t offsets_size; + size_t extra_buffers_size; + uint8_t data[0]; +}; + enum binder_deferred_state { BINDER_DEFERRED_PUT_FILES = 0x01, BINDER_DEFERRED_FLUSH = 0x02, BINDER_DEFERRED_RELEASE = 0x04, }; -/** - * struct binder_priority - scheduler policy and priority - * @sched_policy scheduler policy - * @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT - * - * The binder driver supports inheriting the following scheduler policies: - * SCHED_NORMAL - * SCHED_BATCH - * SCHED_FIFO - * SCHED_RR - */ -struct binder_priority { - unsigned int sched_policy; - int prio; -}; - -/** - * struct binder_proc - binder process bookkeeping - * @proc_node: element for binder_procs list - * @threads: rbtree of binder_threads in this proc - * (protected by @inner_lock) - * @nodes: rbtree of binder nodes associated with - * this proc ordered by node->ptr - * (protected by @inner_lock) - * @refs_by_desc: rbtree of refs ordered by ref->desc - * (protected by @outer_lock) - * @refs_by_node: rbtree of refs ordered by ref->node - * (protected by @outer_lock) - * @waiting_threads: threads currently waiting for proc work - * (protected by @inner_lock) - * @pid PID of group_leader of process - * (invariant after initialized) - * @tsk task_struct for group_leader of process - * (invariant after initialized) - * @files files_struct for process - * (invariant after initialized) - * @deferred_work_node: element for binder_deferred_list - * (protected by binder_deferred_lock) - * @deferred_work: bitmap of deferred work to perform - * (protected by binder_deferred_lock) - * @is_dead: process is dead and awaiting free - * when outstanding transactions are cleaned up - * (protected by @inner_lock) - * @todo: list of work for this process - * (protected by @inner_lock) - * @wait: wait queue head to wait for proc work - * (invariant after initialized) - * @stats: per-process binder statistics - * (atomics, no lock needed) - * @delivered_death: list of delivered death notification - * (protected by @inner_lock) - * @max_threads: cap on number of binder threads - * (protected by @inner_lock) - * @requested_threads: number of binder threads requested but not - * yet started. In current implementation, can - * only be 0 or 1. - * (protected by @inner_lock) - * @requested_threads_started: number binder threads started - * (protected by @inner_lock) - * @tmp_ref: temporary reference to indicate proc is in use - * (protected by @inner_lock) - * @default_priority: default scheduler priority - * (invariant after initialized) - * @debugfs_entry: debugfs node - * @alloc: binder allocator bookkeeping - * @context: binder_context for this proc - * (invariant after initialized) - * @inner_lock: can nest under outer_lock and/or node lock - * @outer_lock: no nesting under innor or node lock - * Lock order: 1) outer, 2) node, 3) inner - * - * Bookkeeping structure for binder processes - */ struct binder_proc { struct hlist_node proc_node; struct rb_root threads; struct rb_root nodes; struct rb_root refs_by_desc; struct rb_root refs_by_node; - struct list_head waiting_threads; int pid; + struct vm_area_struct *vma; + struct mm_struct *vma_vm_mm; struct task_struct *tsk; struct files_struct *files; struct hlist_node deferred_work_node; int deferred_work; - bool is_dead; + void *buffer; + ptrdiff_t user_buffer_offset; + struct list_head buffers; + struct rb_root free_buffers; + struct rb_root allocated_buffers; + size_t free_async_space; + + struct page **pages; + size_t buffer_size; + uint32_t buffer_free; struct list_head todo; wait_queue_head_t wait; struct binder_stats stats; @@ -565,13 +365,10 @@ struct binder_proc { int max_threads; int requested_threads; int requested_threads_started; - int tmp_ref; - struct binder_priority default_priority; + int ready_threads; + long default_priority; struct dentry *debugfs_entry; - struct binder_alloc alloc; struct binder_context *context; - spinlock_t inner_lock; - spinlock_t outer_lock; }; enum { @@ -580,60 +377,22 @@ enum { BINDER_LOOPER_STATE_EXITED = 0x04, BINDER_LOOPER_STATE_INVALID = 0x08, BINDER_LOOPER_STATE_WAITING = 0x10, - BINDER_LOOPER_STATE_POLL = 0x20, + BINDER_LOOPER_STATE_NEED_RETURN = 0x20 }; -/** - * struct binder_thread - binder thread bookkeeping - * @proc: binder process for this thread - * (invariant after initialization) - * @rb_node: element for proc->threads rbtree - * (protected by @proc->inner_lock) - * @waiting_thread_node: element for @proc->waiting_threads list - * (protected by @proc->inner_lock) - * @pid: PID for this thread - * (invariant after initialization) - * @looper: bitmap of looping state - * (only accessed by this thread) - * @looper_needs_return: looping thread needs to exit driver - * (no lock needed) - * @transaction_stack: stack of in-progress transactions for this thread - * (protected by @proc->inner_lock) - * @todo: list of work to do for this thread - * (protected by @proc->inner_lock) - * @return_error: transaction errors reported by this thread - * (only accessed by this thread) - * @reply_error: transaction errors reported by target thread - * (protected by @proc->inner_lock) - * @wait: wait queue for thread work - * @stats: per-thread statistics - * (atomics, no lock needed) - * @tmp_ref: temporary reference to indicate thread is in use - * (atomic since @proc->inner_lock cannot - * always be acquired) - * @is_dead: thread is dead and awaiting free - * when outstanding transactions are cleaned up - * (protected by @proc->inner_lock) - * @task: struct task_struct for this thread - * - * Bookkeeping structure for binder threads. - */ struct binder_thread { struct binder_proc *proc; struct rb_node rb_node; - struct list_head waiting_thread_node; int pid; - int looper; /* only modified by this thread */ - bool looper_need_return; /* can be written by other thread */ + int looper; struct binder_transaction *transaction_stack; struct list_head todo; - struct binder_error return_error; - struct binder_error reply_error; + uint32_t return_error; /* Write failed, return error code in read buf */ + uint32_t return_error2; /* Write failed, return error code in read */ + /* buffer. Used when sending a reply to a dead process that */ + /* we are also waiting on */ wait_queue_head_t wait; struct binder_stats stats; - atomic_t tmp_ref; - bool is_dead; - struct task_struct *task; }; struct binder_transaction { @@ -650,263 +409,20 @@ struct binder_transaction { struct binder_buffer *buffer; unsigned int code; unsigned int flags; - struct binder_priority priority; - struct binder_priority saved_priority; - bool set_priority_called; + long priority; + long saved_priority; kuid_t sender_euid; - /** - * @lock: protects @from, @to_proc, and @to_thread - * - * @from, @to_proc, and @to_thread can be set to NULL - * during thread teardown - */ - spinlock_t lock; }; -/** - * binder_proc_lock() - Acquire outer lock for given binder_proc - * @proc: struct binder_proc to acquire - * - * Acquires proc->outer_lock. Used to protect binder_ref - * structures associated with the given proc. - */ -#define binder_proc_lock(proc) _binder_proc_lock(proc, __LINE__) -static void -_binder_proc_lock(struct binder_proc *proc, int line) -{ - binder_debug(BINDER_DEBUG_SPINLOCKS, - "%s: line=%d\n", __func__, line); - spin_lock(&proc->outer_lock); -} - -/** - * binder_proc_unlock() - Release spinlock for given binder_proc - * @proc: struct binder_proc to acquire - * - * Release lock acquired via binder_proc_lock() - */ -#define binder_proc_unlock(_proc) _binder_proc_unlock(_proc, __LINE__) -static void -_binder_proc_unlock(struct binder_proc *proc, int line) -{ - binder_debug(BINDER_DEBUG_SPINLOCKS, - "%s: line=%d\n", __func__, line); - spin_unlock(&proc->outer_lock); -} - -/** - * binder_inner_proc_lock() - Acquire inner lock for given binder_proc - * @proc: struct binder_proc to acquire - * - * Acquires proc->inner_lock. Used to protect todo lists - */ -#define binder_inner_proc_lock(proc) _binder_inner_proc_lock(proc, __LINE__) -static void -_binder_inner_proc_lock(struct binder_proc *proc, int line) -{ - binder_debug(BINDER_DEBUG_SPINLOCKS, - "%s: line=%d\n", __func__, line); - spin_lock(&proc->inner_lock); -} - -/** - * binder_inner_proc_unlock() - Release inner lock for given binder_proc - * @proc: struct binder_proc to acquire - * - * Release lock acquired via binder_inner_proc_lock() - */ -#define binder_inner_proc_unlock(proc) _binder_inner_proc_unlock(proc, __LINE__) -static void -_binder_inner_proc_unlock(struct binder_proc *proc, int line) -{ - binder_debug(BINDER_DEBUG_SPINLOCKS, - "%s: line=%d\n", __func__, line); - spin_unlock(&proc->inner_lock); -} - -/** - * binder_node_lock() - Acquire spinlock for given binder_node - * @node: struct binder_node to acquire - * - * Acquires node->lock. Used to protect binder_node fields - */ -#define binder_node_lock(node) _binder_node_lock(node, __LINE__) -static void -_binder_node_lock(struct binder_node *node, int line) -{ - binder_debug(BINDER_DEBUG_SPINLOCKS, - "%s: line=%d\n", __func__, line); - spin_lock(&node->lock); -} - -/** - * binder_node_unlock() - Release spinlock for given binder_proc - * @node: struct binder_node to acquire - * - * Release lock acquired via binder_node_lock() - */ -#define binder_node_unlock(node) _binder_node_unlock(node, __LINE__) -static void -_binder_node_unlock(struct binder_node *node, int line) -{ - binder_debug(BINDER_DEBUG_SPINLOCKS, - "%s: line=%d\n", __func__, line); - spin_unlock(&node->lock); -} - -/** - * binder_node_inner_lock() - Acquire node and inner locks - * @node: struct binder_node to acquire - * - * Acquires node->lock. If node->proc also acquires - * proc->inner_lock. Used to protect binder_node fields - */ -#define binder_node_inner_lock(node) _binder_node_inner_lock(node, __LINE__) -static void -_binder_node_inner_lock(struct binder_node *node, int line) -{ - binder_debug(BINDER_DEBUG_SPINLOCKS, - "%s: line=%d\n", __func__, line); - spin_lock(&node->lock); - if (node->proc) - binder_inner_proc_lock(node->proc); -} - -/** - * binder_node_unlock() - Release node and inner locks - * @node: struct binder_node to acquire - * - * Release lock acquired via binder_node_lock() - */ -#define binder_node_inner_unlock(node) _binder_node_inner_unlock(node, __LINE__) -static void -_binder_node_inner_unlock(struct binder_node *node, int line) -{ - struct binder_proc *proc = node->proc; - - binder_debug(BINDER_DEBUG_SPINLOCKS, - "%s: line=%d\n", __func__, line); - if (proc) - binder_inner_proc_unlock(proc); - spin_unlock(&node->lock); -} - -static bool binder_worklist_empty_ilocked(struct list_head *list) -{ - return list_empty(list); -} - -/** - * binder_worklist_empty() - Check if no items on the work list - * @proc: binder_proc associated with list - * @list: list to check - * - * Return: true if there are no items on list, else false - */ -static bool binder_worklist_empty(struct binder_proc *proc, - struct list_head *list) -{ - bool ret; - - binder_inner_proc_lock(proc); - ret = binder_worklist_empty_ilocked(list); - binder_inner_proc_unlock(proc); - return ret; -} - -static void -binder_enqueue_work_ilocked(struct binder_work *work, - struct list_head *target_list) -{ - BUG_ON(target_list == NULL); - BUG_ON(work->entry.next && !list_empty(&work->entry)); - list_add_tail(&work->entry, target_list); -} - -/** - * binder_enqueue_work() - Add an item to the work list - * @proc: binder_proc associated with list - * @work: struct binder_work to add to list - * @target_list: list to add work to - * - * Adds the work to the specified list. Asserts that work - * is not already on a list. - */ -static void -binder_enqueue_work(struct binder_proc *proc, - struct binder_work *work, - struct list_head *target_list) -{ - binder_inner_proc_lock(proc); - binder_enqueue_work_ilocked(work, target_list); - binder_inner_proc_unlock(proc); -} - -static void -binder_dequeue_work_ilocked(struct binder_work *work) -{ - list_del_init(&work->entry); -} - -/** - * binder_dequeue_work() - Removes an item from the work list - * @proc: binder_proc associated with list - * @work: struct binder_work to remove from list - * - * Removes the specified work item from whatever list it is on. - * Can safely be called if work is not on any list. - */ -static void -binder_dequeue_work(struct binder_proc *proc, struct binder_work *work) -{ - binder_inner_proc_lock(proc); - binder_dequeue_work_ilocked(work); - binder_inner_proc_unlock(proc); -} - -static struct binder_work *binder_dequeue_work_head_ilocked( - struct list_head *list) -{ - struct binder_work *w; - - w = list_first_entry_or_null(list, struct binder_work, entry); - if (w) - list_del_init(&w->entry); - return w; -} - -/** - * binder_dequeue_work_head() - Dequeues the item at head of list - * @proc: binder_proc associated with list - * @list: list to dequeue head - * - * Removes the head of the list if there are items on the list - * - * Return: pointer dequeued binder_work, NULL if list was empty - */ -static struct binder_work *binder_dequeue_work_head( - struct binder_proc *proc, - struct list_head *list) -{ - struct binder_work *w; - - binder_inner_proc_lock(proc); - w = binder_dequeue_work_head_ilocked(list); - binder_inner_proc_unlock(proc); - return w; -} - static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); -static void binder_free_thread(struct binder_thread *thread); -static void binder_free_proc(struct binder_proc *proc); -static void binder_inc_node_tmpref_ilocked(struct binder_node *node); static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { struct files_struct *files = proc->files; unsigned long rlim_cur; unsigned long irqs; + int ret; if (files == NULL) return -ESRCH; @@ -917,7 +433,11 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); unlock_task_sighand(proc->tsk, &irqs); - return __alloc_fd(files, 0, rlim_cur, flags); + preempt_enable_no_resched(); + ret = __alloc_fd(files, 0, rlim_cur, flags); + preempt_disable(); + + return ret; } /* @@ -926,8 +446,11 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) static void task_fd_install( struct binder_proc *proc, unsigned int fd, struct file *file) { - if (proc->files) + if (proc->files) { + preempt_enable_no_resched(); __fd_install(proc->files, fd, file); + preempt_disable(); + } } /* @@ -951,281 +474,532 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) return retval; } -static bool binder_has_work_ilocked(struct binder_thread *thread, - bool do_proc_work) +static inline int binder_lock(struct binder_context *context, const char *tag) { - return !binder_worklist_empty_ilocked(&thread->todo) || - thread->looper_need_return || - (do_proc_work && - !binder_worklist_empty_ilocked(&thread->proc->todo)); + int err = 0; + trace_binder_lock(tag); + err = mutex_lock_killable(&context->binder_main_lock); + if (err) { + pr_err("Unable to lock binder_main_lock, returns error =%d\n", err); + return err; + } + preempt_disable(); + trace_binder_locked(tag); + return err; } -static bool binder_has_work(struct binder_thread *thread, bool do_proc_work) +static inline void binder_unlock(struct binder_context *context, + const char *tag) { - bool has_work; - - binder_inner_proc_lock(thread->proc); - has_work = binder_has_work_ilocked(thread, do_proc_work); - binder_inner_proc_unlock(thread->proc); - - return has_work; + trace_binder_unlock(tag); + mutex_unlock(&context->binder_main_lock); + preempt_enable(); } -static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread) +static inline void *kzalloc_preempt_disabled(size_t size) { - return !thread->transaction_stack && - binder_worklist_empty_ilocked(&thread->todo) && - (thread->looper & (BINDER_LOOPER_STATE_ENTERED | - BINDER_LOOPER_STATE_REGISTERED)); -} + void *ptr; -static void binder_wakeup_poll_threads_ilocked(struct binder_proc *proc, - bool sync) -{ - struct rb_node *n; - struct binder_thread *thread; + ptr = kzalloc(size, GFP_NOWAIT); + if (ptr) + return ptr; - for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { - thread = rb_entry(n, struct binder_thread, rb_node); - if (thread->looper & BINDER_LOOPER_STATE_POLL && - binder_available_for_proc_work_ilocked(thread)) { - if (sync) - wake_up_interruptible_sync(&thread->wait); - else - wake_up_interruptible(&thread->wait); - } - } + preempt_enable_no_resched(); + ptr = kzalloc(size, GFP_KERNEL); + preempt_disable(); + + return ptr; } -/** - * binder_select_thread_ilocked() - selects a thread for doing proc work. - * @proc: process to select a thread from - * - * Note that calling this function moves the thread off the waiting_threads - * list, so it can only be woken up by the caller of this function, or a - * signal. Therefore, callers *should* always wake up the thread this function - * returns. - * - * Return: If there's a thread currently waiting for process work, - * returns that thread. Otherwise returns NULL. - */ -static struct binder_thread * -binder_select_thread_ilocked(struct binder_proc *proc) +static inline long copy_to_user_preempt_disabled(void __user *to, const void *from, long n) { - struct binder_thread *thread; + long ret; - BUG_ON(!spin_is_locked(&proc->inner_lock)); - thread = list_first_entry_or_null(&proc->waiting_threads, - struct binder_thread, - waiting_thread_node); + preempt_enable_no_resched(); + ret = copy_to_user(to, from, n); + preempt_disable(); + return ret; +} - if (thread) - list_del_init(&thread->waiting_thread_node); +static inline long copy_from_user_preempt_disabled(void *to, const void __user *from, long n) +{ + long ret; - return thread; + preempt_enable_no_resched(); + ret = copy_from_user(to, from, n); + preempt_disable(); + return ret; } -/** - * binder_wakeup_thread_ilocked() - wakes up a thread for doing proc work. - * @proc: process to wake up a thread in - * @thread: specific thread to wake-up (may be NULL) - * @sync: whether to do a synchronous wake-up - * - * This function wakes up a thread in the @proc process. - * The caller may provide a specific thread to wake-up in - * the @thread parameter. If @thread is NULL, this function - * will wake up threads that have called poll(). - * - * Note that for this function to work as expected, callers - * should first call binder_select_thread() to find a thread - * to handle the work (if they don't have a thread already), - * and pass the result into the @thread parameter. - */ -static void binder_wakeup_thread_ilocked(struct binder_proc *proc, - struct binder_thread *thread, - bool sync) +#define get_user_preempt_disabled(x, ptr) \ +({ \ + int __ret; \ + preempt_enable_no_resched(); \ + __ret = get_user(x, ptr); \ + preempt_disable(); \ + __ret; \ +}) + +#define put_user_preempt_disabled(x, ptr) \ +({ \ + int __ret; \ + preempt_enable_no_resched(); \ + __ret = put_user(x, ptr); \ + preempt_disable(); \ + __ret; \ +}) + +static void binder_set_nice(long nice) { - BUG_ON(!spin_is_locked(&proc->inner_lock)); + long min_nice; - if (thread) { - if (sync) - wake_up_interruptible_sync(&thread->wait); - else - wake_up_interruptible(&thread->wait); + if (can_nice(current, nice)) { + set_user_nice(current, nice); return; } - - /* Didn't find a thread waiting for proc work; this can happen - * in two scenarios: - * 1. All threads are busy handling transactions - * In that case, one of those threads should call back into - * the kernel driver soon and pick up this work. - * 2. Threads are using the (e)poll interface, in which case - * they may be blocked on the waitqueue without having been - * added to waiting_threads. For this case, we just iterate - * over all threads not handling transaction work, and - * wake them all up. We wake all because we don't know whether - * a thread that called into (e)poll is handling non-binder - * work currently. - */ - binder_wakeup_poll_threads_ilocked(proc, sync); + min_nice = rlimit_to_nice(current->signal->rlim[RLIMIT_NICE].rlim_cur); + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "%d: nice value %ld not allowed use %ld instead\n", + current->pid, nice, min_nice); + set_user_nice(current, min_nice); + if (min_nice <= MAX_NICE) + return; + binder_user_error("%d RLIMIT_NICE not set\n", current->pid); } -static void binder_wakeup_proc_ilocked(struct binder_proc *proc) +static size_t binder_buffer_size(struct binder_proc *proc, + struct binder_buffer *buffer) { - struct binder_thread *thread = binder_select_thread_ilocked(proc); - - binder_wakeup_thread_ilocked(proc, thread, /* sync = */false); + if (list_is_last(&buffer->entry, &proc->buffers)) + return proc->buffer + proc->buffer_size - (void *)buffer->data; + return (size_t)list_entry(buffer->entry.next, + struct binder_buffer, entry) - (size_t)buffer->data; } -static bool is_rt_policy(int policy) +static void binder_insert_free_buffer(struct binder_proc *proc, + struct binder_buffer *new_buffer) { - return policy == SCHED_FIFO || policy == SCHED_RR; -} + struct rb_node **p = &proc->free_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + size_t buffer_size; + size_t new_buffer_size; -static bool is_fair_policy(int policy) -{ - return policy == SCHED_NORMAL || policy == SCHED_BATCH; -} + BUG_ON(!new_buffer->free); -static bool binder_supported_policy(int policy) -{ - return is_fair_policy(policy) || is_rt_policy(policy); + new_buffer_size = binder_buffer_size(proc, new_buffer); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: add free buffer, size %zd, at %p\n", + proc->pid, new_buffer_size, new_buffer); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + + buffer_size = binder_buffer_size(proc, buffer); + + if (new_buffer_size < buffer_size) + p = &parent->rb_left; + else + p = &parent->rb_right; + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &proc->free_buffers); } -static int to_userspace_prio(int policy, int kernel_priority) +static void binder_insert_allocated_buffer(struct binder_proc *proc, + struct binder_buffer *new_buffer) { - if (is_fair_policy(policy)) - return PRIO_TO_NICE(kernel_priority); - else - return MAX_USER_RT_PRIO - 1 - kernel_priority; + struct rb_node **p = &proc->allocated_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + + BUG_ON(new_buffer->free); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (new_buffer < buffer) + p = &parent->rb_left; + else if (new_buffer > buffer) + p = &parent->rb_right; + else + BUG(); + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &proc->allocated_buffers); } -static int to_kernel_prio(int policy, int user_priority) +static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, + uintptr_t user_ptr) { - if (is_fair_policy(policy)) - return NICE_TO_PRIO(user_priority); - else - return MAX_USER_RT_PRIO - 1 - user_priority; + struct rb_node *n = proc->allocated_buffers.rb_node; + struct binder_buffer *buffer; + struct binder_buffer *kern_ptr; + + kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset + - offsetof(struct binder_buffer, data)); + + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (kern_ptr < buffer) + n = n->rb_left; + else if (kern_ptr > buffer) + n = n->rb_right; + else + return buffer; + } + return NULL; } -static void binder_do_set_priority(struct task_struct *task, - struct binder_priority desired, - bool verify) +static int binder_update_page_range(struct binder_proc *proc, int allocate, + void *start, void *end, + struct vm_area_struct *vma) { - int priority; /* user-space prio value */ - bool has_cap_nice; - unsigned int policy = desired.sched_policy; + void *page_addr; + unsigned long user_page_addr; + struct page **page; + struct mm_struct *mm; - if (task->policy == policy && task->normal_prio == desired.prio) - return; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: %s pages %p-%p\n", proc->pid, + allocate ? "allocate" : "free", start, end); - has_cap_nice = has_capability_noaudit(task, CAP_SYS_NICE); + if (end <= start) + return 0; + + trace_binder_update_page_range(proc, allocate, start, end); - priority = to_userspace_prio(policy, desired.prio); + if (vma) + mm = NULL; + else + mm = get_task_mm(proc->tsk); - if (verify && is_rt_policy(policy) && !has_cap_nice) { - long max_rtprio = task_rlimit(task, RLIMIT_RTPRIO); + preempt_enable_no_resched(); - if (max_rtprio == 0) { - policy = SCHED_NORMAL; - priority = MIN_NICE; - } else if (priority > max_rtprio) { - priority = max_rtprio; + if (mm) { + down_write(&mm->mmap_sem); + vma = proc->vma; + if (vma && mm != proc->vma_vm_mm) { + pr_err("%d: vma mm and task mm mismatch\n", + proc->pid); + vma = NULL; } } - if (verify && is_fair_policy(policy) && !has_cap_nice) { - long min_nice = rlimit_to_nice(task_rlimit(task, RLIMIT_NICE)); + if (allocate == 0) + goto free_range; - if (min_nice > MAX_NICE) { - binder_user_error("%d RLIMIT_NICE not set\n", - task->pid); - return; - } else if (priority < min_nice) { - priority = min_nice; + if (vma == NULL) { + pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", + proc->pid); + goto err_no_vma; + } + + for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { + int ret; + + page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; + + BUG_ON(*page); + *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); + if (*page == NULL) { + pr_err("%d: binder_alloc_buf failed for page at %p\n", + proc->pid, page_addr); + goto err_alloc_page_failed; } + ret = map_kernel_range_noflush((unsigned long)page_addr, + PAGE_SIZE, PAGE_KERNEL, page); + flush_cache_vmap((unsigned long)page_addr, + (unsigned long)page_addr + PAGE_SIZE); + if (ret != 1) { + pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n", + proc->pid, page_addr); + goto err_map_kernel_failed; + } + user_page_addr = + (uintptr_t)page_addr + proc->user_buffer_offset; + ret = vm_insert_page(vma, user_page_addr, page[0]); + if (ret) { + pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", + proc->pid, user_page_addr); + goto err_vm_insert_page_failed; + } + /* vm_insert_page does not seem to increment the refcount */ + } + if (mm) { + up_write(&mm->mmap_sem); + mmput(mm); + } + + preempt_disable(); + + return 0; + +free_range: + for (page_addr = end - PAGE_SIZE; page_addr >= start; + page_addr -= PAGE_SIZE) { + page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; + if (vma) + zap_page_range(vma, (uintptr_t)page_addr + + proc->user_buffer_offset, PAGE_SIZE, NULL); +err_vm_insert_page_failed: + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); +err_map_kernel_failed: + __free_page(*page); + *page = NULL; +err_alloc_page_failed: + ; + } +err_no_vma: + if (mm) { + up_write(&mm->mmap_sem); + mmput(mm); + } + + preempt_disable(); + + return -ENOMEM; +} + +static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async) +{ + struct rb_node *n = proc->free_buffers.rb_node; + struct binder_buffer *buffer; + size_t buffer_size; + struct rb_node *best_fit = NULL; + void *has_page_addr; + void *end_page_addr; + size_t size, data_offsets_size; + + if (proc->vma == NULL) { + pr_err("%d: binder_alloc_buf, no vma\n", + proc->pid); + return NULL; } - if (policy != desired.sched_policy || - to_kernel_prio(policy, priority) != desired.prio) - binder_debug(BINDER_DEBUG_PRIORITY_CAP, - "%d: priority %d not allowed, using %d instead\n", - task->pid, desired.prio, - to_kernel_prio(policy, priority)); + data_offsets_size = ALIGN(data_size, sizeof(void *)) + + ALIGN(offsets_size, sizeof(void *)); - /* Set the actual priority */ - if (task->policy != policy || is_rt_policy(policy)) { - struct sched_param params; + if (data_offsets_size < data_size || data_offsets_size < offsets_size) { + binder_user_error("%d: got transaction with invalid size %zd-%zd\n", + proc->pid, data_size, offsets_size); + return NULL; + } + size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); + if (size < data_offsets_size || size < extra_buffers_size) { + binder_user_error("%d: got transaction with invalid extra_buffers_size %zd\n", + proc->pid, extra_buffers_size); + return NULL; + } + if (is_async && + proc->free_async_space < size + sizeof(struct binder_buffer)) { + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd failed, no async space left\n", + proc->pid, size); + return NULL; + } - params.sched_priority = is_rt_policy(policy) ? priority : 0; + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + buffer_size = binder_buffer_size(proc, buffer); - sched_setscheduler_nocheck(task, - policy | SCHED_RESET_ON_FORK, - ¶ms); + if (size < buffer_size) { + best_fit = n; + n = n->rb_left; + } else if (size > buffer_size) + n = n->rb_right; + else { + best_fit = n; + break; + } } - if (is_fair_policy(policy)) - set_user_nice(task, priority); + if (best_fit == NULL) { + pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", + proc->pid, size); + return NULL; + } + if (n == NULL) { + buffer = rb_entry(best_fit, struct binder_buffer, rb_node); + buffer_size = binder_buffer_size(proc, buffer); + } + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got buffer %p size %zd\n", + proc->pid, size, buffer, buffer_size); + + has_page_addr = + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); + if (n == NULL) { + if (size + sizeof(struct binder_buffer) + 4 >= buffer_size) + buffer_size = size; /* no room for other buffers */ + else + buffer_size = size + sizeof(struct binder_buffer); + } + end_page_addr = + (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size); + if (end_page_addr > has_page_addr) + end_page_addr = has_page_addr; + if (binder_update_page_range(proc, 1, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL)) + return NULL; + + rb_erase(best_fit, &proc->free_buffers); + buffer->free = 0; + binder_insert_allocated_buffer(proc, buffer); + if (buffer_size != size) { + struct binder_buffer *new_buffer = (void *)buffer->data + size; + + list_add(&new_buffer->entry, &buffer->entry); + new_buffer->free = 1; + binder_insert_free_buffer(proc, new_buffer); + } + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got %p\n", + proc->pid, size, buffer); + buffer->data_size = data_size; + buffer->offsets_size = offsets_size; + buffer->extra_buffers_size = extra_buffers_size; + buffer->async_transaction = is_async; + if (is_async) { + proc->free_async_space -= size + sizeof(struct binder_buffer); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_alloc_buf size %zd async free %zd\n", + proc->pid, size, proc->free_async_space); + } + + return buffer; } -static void binder_set_priority(struct task_struct *task, - struct binder_priority desired) +static void *buffer_start_page(struct binder_buffer *buffer) { - binder_do_set_priority(task, desired, /* verify = */ true); + return (void *)((uintptr_t)buffer & PAGE_MASK); } -static void binder_restore_priority(struct task_struct *task, - struct binder_priority desired) +static void *buffer_end_page(struct binder_buffer *buffer) { - binder_do_set_priority(task, desired, /* verify = */ false); + return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK); } -static void binder_transaction_priority(struct task_struct *task, - struct binder_transaction *t, - struct binder_priority node_prio, - bool inherit_rt) +static void binder_delete_free_buffer(struct binder_proc *proc, + struct binder_buffer *buffer) { - struct binder_priority desired_prio; + struct binder_buffer *prev, *next = NULL; + int free_page_end = 1; + int free_page_start = 1; + + BUG_ON(proc->buffers.next == &buffer->entry); + prev = list_entry(buffer->entry.prev, struct binder_buffer, entry); + BUG_ON(!prev->free); + if (buffer_end_page(prev) == buffer_start_page(buffer)) { + free_page_start = 0; + if (buffer_end_page(prev) == buffer_end_page(buffer)) + free_page_end = 0; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %p share page with %p\n", + proc->pid, buffer, prev); + } - if (t->set_priority_called) - return; + if (!list_is_last(&buffer->entry, &proc->buffers)) { + next = list_entry(buffer->entry.next, + struct binder_buffer, entry); + if (buffer_start_page(next) == buffer_end_page(buffer)) { + free_page_end = 0; + if (buffer_start_page(next) == + buffer_start_page(buffer)) + free_page_start = 0; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %p share page with %p\n", + proc->pid, buffer, prev); + } + } + list_del(&buffer->entry); + if (free_page_start || free_page_end) { + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %p do not share page%s%s with %p or %p\n", + proc->pid, buffer, free_page_start ? "" : " end", + free_page_end ? "" : " start", prev, next); + binder_update_page_range(proc, 0, free_page_start ? + buffer_start_page(buffer) : buffer_end_page(buffer), + (free_page_end ? buffer_end_page(buffer) : + buffer_start_page(buffer)) + PAGE_SIZE, NULL); + } +} - t->set_priority_called = true; - t->saved_priority.sched_policy = task->policy; - t->saved_priority.prio = task->normal_prio; +static void binder_free_buf(struct binder_proc *proc, + struct binder_buffer *buffer) +{ + size_t size, buffer_size; - if (!inherit_rt && is_rt_policy(desired_prio.sched_policy)) { - desired_prio.prio = NICE_TO_PRIO(0); - desired_prio.sched_policy = SCHED_NORMAL; - } else { - desired_prio.prio = t->priority.prio; - desired_prio.sched_policy = t->priority.sched_policy; - } + buffer_size = binder_buffer_size(proc, buffer); - if (node_prio.prio < t->priority.prio || - (node_prio.prio == t->priority.prio && - node_prio.sched_policy == SCHED_FIFO)) { - /* - * In case the minimum priority on the node is - * higher (lower value), use that priority. If - * the priority is the same, but the node uses - * SCHED_FIFO, prefer SCHED_FIFO, since it can - * run unbounded, unlike SCHED_RR. - */ - desired_prio = node_prio; + size = ALIGN(buffer->data_size, sizeof(void *)) + + ALIGN(buffer->offsets_size, sizeof(void *)) + + ALIGN(buffer->extra_buffers_size, sizeof(void *)); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_free_buf %p size %zd buffer_size %zd\n", + proc->pid, buffer, size, buffer_size); + + BUG_ON(buffer->free); + BUG_ON(size > buffer_size); + BUG_ON(buffer->transaction != NULL); + BUG_ON((void *)buffer < proc->buffer); + BUG_ON((void *)buffer > proc->buffer + proc->buffer_size); + + if (buffer->async_transaction) { + proc->free_async_space += size + sizeof(struct binder_buffer); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_free_buf size %zd async free %zd\n", + proc->pid, size, proc->free_async_space); } - binder_set_priority(task, desired_prio); + binder_update_page_range(proc, 0, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), + NULL); + rb_erase(&buffer->rb_node, &proc->allocated_buffers); + buffer->free = 1; + if (!list_is_last(&buffer->entry, &proc->buffers)) { + struct binder_buffer *next = list_entry(buffer->entry.next, + struct binder_buffer, entry); + + if (next->free) { + rb_erase(&next->rb_node, &proc->free_buffers); + binder_delete_free_buffer(proc, next); + } + } + if (proc->buffers.next != &buffer->entry) { + struct binder_buffer *prev = list_entry(buffer->entry.prev, + struct binder_buffer, entry); + + if (prev->free) { + binder_delete_free_buffer(proc, buffer); + rb_erase(&prev->rb_node, &proc->free_buffers); + buffer = prev; + } + } + binder_insert_free_buffer(proc, buffer); } -static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc, - binder_uintptr_t ptr) +static struct binder_node *binder_get_node(struct binder_proc *proc, + binder_uintptr_t ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; - BUG_ON(!spin_is_locked(&proc->inner_lock)); - while (n) { node = rb_entry(n, struct binder_node, rb_node); @@ -1233,46 +1007,21 @@ static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc, n = n->rb_left; else if (ptr > node->ptr) n = n->rb_right; - else { - /* - * take an implicit weak reference - * to ensure node stays alive until - * call to binder_put_node() - */ - binder_inc_node_tmpref_ilocked(node); + else return node; - } } return NULL; } -static struct binder_node *binder_get_node(struct binder_proc *proc, - binder_uintptr_t ptr) -{ - struct binder_node *node; - - binder_inner_proc_lock(proc); - node = binder_get_node_ilocked(proc, ptr); - binder_inner_proc_unlock(proc); - return node; -} - -static struct binder_node *binder_init_node_ilocked( - struct binder_proc *proc, - struct binder_node *new_node, - struct flat_binder_object *fp) +static struct binder_node *binder_new_node(struct binder_proc *proc, + binder_uintptr_t ptr, + binder_uintptr_t cookie) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; struct binder_node *node; - binder_uintptr_t ptr = fp ? fp->binder : 0; - binder_uintptr_t cookie = fp ? fp->cookie : 0; - __u32 flags = fp ? fp->flags : 0; - s8 priority; - BUG_ON(!spin_is_locked(&proc->inner_lock)); while (*p) { - parent = *p; node = rb_entry(parent, struct binder_node, rb_node); @@ -1280,19 +1029,14 @@ static struct binder_node *binder_init_node_ilocked( p = &(*p)->rb_left; else if (ptr > node->ptr) p = &(*p)->rb_right; - else { - /* - * A matching node is already in - * the rb tree. Abandon the init - * and return it. - */ - binder_inc_node_tmpref_ilocked(node); - return node; - } + else + return NULL; } - node = new_node; + + node = kzalloc_preempt_disabled(sizeof(*node)); + if (node == NULL) + return NULL; binder_stats_created(BINDER_STAT_NODE); - node->tmp_refs++; rb_link_node(&node->rb_node, parent, p); rb_insert_color(&node->rb_node, &proc->nodes); node->debug_id = atomic_inc_return(&binder_last_id); @@ -1300,58 +1044,18 @@ static struct binder_node *binder_init_node_ilocked( node->ptr = ptr; node->cookie = cookie; node->work.type = BINDER_WORK_NODE; - priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK; - node->sched_policy = (flags & FLAT_BINDER_FLAG_PRIORITY_MASK) >> - FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT; - node->min_priority = to_kernel_prio(node->sched_policy, priority); - node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); - node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT); - spin_lock_init(&node->lock); INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "%d:%d node %d u%016llx c%016llx created\n", proc->pid, current->pid, node->debug_id, (u64)node->ptr, (u64)node->cookie); - - return node; -} - -static struct binder_node *binder_new_node(struct binder_proc *proc, - struct flat_binder_object *fp) -{ - struct binder_node *node; - struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL); - - if (!new_node) - return NULL; - binder_inner_proc_lock(proc); - node = binder_init_node_ilocked(proc, new_node, fp); - binder_inner_proc_unlock(proc); - if (node != new_node) - /* - * The node was already added by another thread - */ - kfree(new_node); - return node; } -static void binder_free_node(struct binder_node *node) -{ - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); -} - -static int binder_inc_node_nilocked(struct binder_node *node, int strong, - int internal, - struct list_head *target_list) +static int binder_inc_node(struct binder_node *node, int strong, int internal, + struct list_head *target_list) { - struct binder_proc *proc = node->proc; - - BUG_ON(!spin_is_locked(&node->lock)); - if (proc) - BUG_ON(!spin_is_locked(&proc->inner_lock)); if (strong) { if (internal) { if (target_list == NULL && @@ -1368,8 +1072,8 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong, } else node->local_strong_refs++; if (!node->has_strong_ref && target_list) { - binder_dequeue_work_ilocked(&node->work); - binder_enqueue_work_ilocked(&node->work, target_list); + list_del_init(&node->work.entry); + list_add_tail(&node->work.entry, target_list); } } else { if (!internal) @@ -1380,169 +1084,58 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong, node->debug_id); return -EINVAL; } - binder_enqueue_work_ilocked(&node->work, target_list); + list_add_tail(&node->work.entry, target_list); } } return 0; } -static int binder_inc_node(struct binder_node *node, int strong, int internal, - struct list_head *target_list) +static int binder_dec_node(struct binder_node *node, int strong, int internal) { - int ret; - - binder_node_inner_lock(node); - ret = binder_inc_node_nilocked(node, strong, internal, target_list); - binder_node_inner_unlock(node); - - return ret; -} - -static bool binder_dec_node_nilocked(struct binder_node *node, - int strong, int internal) -{ - struct binder_proc *proc = node->proc; - - BUG_ON(!spin_is_locked(&node->lock)); - if (proc) - BUG_ON(!spin_is_locked(&proc->inner_lock)); if (strong) { if (internal) node->internal_strong_refs--; else node->local_strong_refs--; if (node->local_strong_refs || node->internal_strong_refs) - return false; + return 0; } else { if (!internal) node->local_weak_refs--; - if (node->local_weak_refs || node->tmp_refs || - !hlist_empty(&node->refs)) - return false; + if (node->local_weak_refs || !hlist_empty(&node->refs)) + return 0; } - - if (proc && (node->has_strong_ref || node->has_weak_ref)) { + if (node->proc && (node->has_strong_ref || node->has_weak_ref)) { if (list_empty(&node->work.entry)) { - binder_enqueue_work_ilocked(&node->work, &proc->todo); - binder_wakeup_proc_ilocked(proc); + list_add_tail(&node->work.entry, &node->proc->todo); + wake_up_interruptible(&node->proc->wait); } } else { if (hlist_empty(&node->refs) && !node->local_strong_refs && - !node->local_weak_refs && !node->tmp_refs) { - if (proc) { - binder_dequeue_work_ilocked(&node->work); - rb_erase(&node->rb_node, &proc->nodes); + !node->local_weak_refs) { + list_del_init(&node->work.entry); + if (node->proc) { + rb_erase(&node->rb_node, &node->proc->nodes); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "refless node %d deleted\n", node->debug_id); } else { - BUG_ON(!list_empty(&node->work.entry)); - spin_lock(&binder_dead_nodes_lock); - /* - * tmp_refs could have changed so - * check it again - */ - if (node->tmp_refs) { - spin_unlock(&binder_dead_nodes_lock); - return false; - } hlist_del(&node->dead_node); - spin_unlock(&binder_dead_nodes_lock); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "dead node %d deleted\n", node->debug_id); } - return true; + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); } } - return false; -} -static void binder_dec_node(struct binder_node *node, int strong, int internal) -{ - bool free_node; - - binder_node_inner_lock(node); - free_node = binder_dec_node_nilocked(node, strong, internal); - binder_node_inner_unlock(node); - if (free_node) - binder_free_node(node); -} - -static void binder_inc_node_tmpref_ilocked(struct binder_node *node) -{ - /* - * No call to binder_inc_node() is needed since we - * don't need to inform userspace of any changes to - * tmp_refs - */ - node->tmp_refs++; -} - -/** - * binder_inc_node_tmpref() - take a temporary reference on node - * @node: node to reference - * - * Take reference on node to prevent the node from being freed - * while referenced only by a local variable. The inner lock is - * needed to serialize with the node work on the queue (which - * isn't needed after the node is dead). If the node is dead - * (node->proc is NULL), use binder_dead_nodes_lock to protect - * node->tmp_refs against dead-node-only cases where the node - * lock cannot be acquired (eg traversing the dead node list to - * print nodes) - */ -static void binder_inc_node_tmpref(struct binder_node *node) -{ - binder_node_lock(node); - if (node->proc) - binder_inner_proc_lock(node->proc); - else - spin_lock(&binder_dead_nodes_lock); - binder_inc_node_tmpref_ilocked(node); - if (node->proc) - binder_inner_proc_unlock(node->proc); - else - spin_unlock(&binder_dead_nodes_lock); - binder_node_unlock(node); + return 0; } -/** - * binder_dec_node_tmpref() - remove a temporary reference on node - * @node: node to reference - * - * Release temporary reference on node taken via binder_inc_node_tmpref() - */ -static void binder_dec_node_tmpref(struct binder_node *node) -{ - bool free_node; - - binder_node_inner_lock(node); - if (!node->proc) - spin_lock(&binder_dead_nodes_lock); - node->tmp_refs--; - BUG_ON(node->tmp_refs < 0); - if (!node->proc) - spin_unlock(&binder_dead_nodes_lock); - /* - * Call binder_dec_node() to check if all refcounts are 0 - * and cleanup is needed. Calling with strong=0 and internal=1 - * causes no actual reference to be released in binder_dec_node(). - * If that changes, a change is needed here too. - */ - free_node = binder_dec_node_nilocked(node, 0, 1); - binder_node_inner_unlock(node); - if (free_node) - binder_free_node(node); -} -static void binder_put_node(struct binder_node *node) -{ - binder_dec_node_tmpref(node); -} - -static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc, - u32 desc, bool need_strong_ref) +static struct binder_ref *binder_get_ref(struct binder_proc *proc, + u32 desc, bool need_strong_ref) { struct rb_node *n = proc->refs_by_desc.rb_node; struct binder_ref *ref; @@ -1550,11 +1143,11 @@ static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc, while (n) { ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (desc < ref->data.desc) { + if (desc < ref->desc) { n = n->rb_left; - } else if (desc > ref->data.desc) { + } else if (desc > ref->desc) { n = n->rb_right; - } else if (need_strong_ref && !ref->data.strong) { + } else if (need_strong_ref && !ref->strong) { binder_user_error("tried to use weak ref as strong ref\n"); return NULL; } else { @@ -1564,34 +1157,14 @@ static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc, return NULL; } -/** - * binder_get_ref_for_node_olocked() - get the ref associated with given node - * @proc: binder_proc that owns the ref - * @node: binder_node of target - * @new_ref: newly allocated binder_ref to be initialized or %NULL - * - * Look up the ref for the given node and return it if it exists - * - * If it doesn't exist and the caller provides a newly allocated - * ref, initialize the fields of the newly allocated ref and insert - * into the given proc rb_trees and node refs list. - * - * Return: the ref for node. It is possible that another thread - * allocated/initialized the ref first in which case the - * returned ref would be different than the passed-in - * new_ref. new_ref must be kfree'd by the caller in - * this case. - */ -static struct binder_ref *binder_get_ref_for_node_olocked( - struct binder_proc *proc, - struct binder_node *node, - struct binder_ref *new_ref) +static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, + struct binder_node *node) { - struct binder_context *context = proc->context; + struct rb_node *n; struct rb_node **p = &proc->refs_by_node.rb_node; struct rb_node *parent = NULL; - struct binder_ref *ref; - struct rb_node *n; + struct binder_ref *ref, *new_ref; + struct binder_context *context = proc->context; while (*p) { parent = *p; @@ -1604,22 +1177,22 @@ static struct binder_ref *binder_get_ref_for_node_olocked( else return ref; } - if (!new_ref) + new_ref = kzalloc_preempt_disabled(sizeof(*ref)); + if (new_ref == NULL) return NULL; - binder_stats_created(BINDER_STAT_REF); - new_ref->data.debug_id = atomic_inc_return(&binder_last_id); + new_ref->debug_id = atomic_inc_return(&binder_last_id); new_ref->proc = proc; new_ref->node = node; rb_link_node(&new_ref->rb_node_node, parent, p); rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node); - new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1; + new_ref->desc = (node == context->binder_context_mgr_node) ? 0 : 1; for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (ref->data.desc > new_ref->data.desc) + if (ref->desc > new_ref->desc) break; - new_ref->data.desc = ref->data.desc + 1; + new_ref->desc = ref->desc + 1; } p = &proc->refs_by_desc.rb_node; @@ -1627,423 +1200,121 @@ static struct binder_ref *binder_get_ref_for_node_olocked( parent = *p; ref = rb_entry(parent, struct binder_ref, rb_node_desc); - if (new_ref->data.desc < ref->data.desc) + if (new_ref->desc < ref->desc) p = &(*p)->rb_left; - else if (new_ref->data.desc > ref->data.desc) + else if (new_ref->desc > ref->desc) p = &(*p)->rb_right; else BUG(); } rb_link_node(&new_ref->rb_node_desc, parent, p); rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc); + if (node) { + hlist_add_head(&new_ref->node_entry, &node->refs); - binder_node_lock(node); - hlist_add_head(&new_ref->node_entry, &node->refs); - - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d new ref %d desc %d for node %d\n", - proc->pid, new_ref->data.debug_id, new_ref->data.desc, - node->debug_id); - binder_node_unlock(node); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d new ref %d desc %d for node %d\n", + proc->pid, new_ref->debug_id, new_ref->desc, + node->debug_id); + } else { + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d new ref %d desc %d for dead node\n", + proc->pid, new_ref->debug_id, new_ref->desc); + } return new_ref; } -static void binder_cleanup_ref_olocked(struct binder_ref *ref) +static void binder_delete_ref(struct binder_ref *ref) { - bool delete_node = false; - binder_debug(BINDER_DEBUG_INTERNAL_REFS, "%d delete ref %d desc %d for node %d\n", - ref->proc->pid, ref->data.debug_id, ref->data.desc, + ref->proc->pid, ref->debug_id, ref->desc, ref->node->debug_id); rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc); rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node); - - binder_node_inner_lock(ref->node); - if (ref->data.strong) - binder_dec_node_nilocked(ref->node, 1, 1); - + if (ref->strong) + binder_dec_node(ref->node, 1, 1); hlist_del(&ref->node_entry); - delete_node = binder_dec_node_nilocked(ref->node, 0, 1); - binder_node_inner_unlock(ref->node); - /* - * Clear ref->node unless we want the caller to free the node - */ - if (!delete_node) { - /* - * The caller uses ref->node to determine - * whether the node needs to be freed. Clear - * it since the node is still alive. - */ - ref->node = NULL; - } - + binder_dec_node(ref->node, 0, 1); if (ref->death) { binder_debug(BINDER_DEBUG_DEAD_BINDER, "%d delete ref %d desc %d has death notification\n", - ref->proc->pid, ref->data.debug_id, - ref->data.desc); - binder_dequeue_work(ref->proc, &ref->death->work); + ref->proc->pid, ref->debug_id, ref->desc); + list_del(&ref->death->work.entry); + kfree(ref->death); binder_stats_deleted(BINDER_STAT_DEATH); } + kfree(ref); binder_stats_deleted(BINDER_STAT_REF); } -/** - * binder_inc_ref_olocked() - increment the ref for given handle - * @ref: ref to be incremented - * @strong: if true, strong increment, else weak - * @target_list: list to queue node work on - * - * Increment the ref. @ref->proc->outer_lock must be held on entry - * - * Return: 0, if successful, else errno - */ -static int binder_inc_ref_olocked(struct binder_ref *ref, int strong, - struct list_head *target_list) +static int binder_inc_ref(struct binder_ref *ref, int strong, + struct list_head *target_list) { int ret; if (strong) { - if (ref->data.strong == 0) { + if (ref->strong == 0) { ret = binder_inc_node(ref->node, 1, 1, target_list); if (ret) return ret; } - ref->data.strong++; + ref->strong++; } else { - if (ref->data.weak == 0) { + if (ref->weak == 0) { ret = binder_inc_node(ref->node, 0, 1, target_list); if (ret) - return ret; - } - ref->data.weak++; - } - return 0; -} - -/** - * binder_dec_ref() - dec the ref for given handle - * @ref: ref to be decremented - * @strong: if true, strong decrement, else weak - * - * Decrement the ref. - * - * Return: true if ref is cleaned up and ready to be freed - */ -static bool binder_dec_ref_olocked(struct binder_ref *ref, int strong) -{ - if (strong) { - if (ref->data.strong == 0) { - binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n", - ref->proc->pid, ref->data.debug_id, - ref->data.desc, ref->data.strong, - ref->data.weak); - return false; - } - ref->data.strong--; - if (ref->data.strong == 0) - binder_dec_node(ref->node, strong, 1); - } else { - if (ref->data.weak == 0) { - binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n", - ref->proc->pid, ref->data.debug_id, - ref->data.desc, ref->data.strong, - ref->data.weak); - return false; - } - ref->data.weak--; - } - if (ref->data.strong == 0 && ref->data.weak == 0) { - binder_cleanup_ref_olocked(ref); - return true; - } - return false; -} - -/** - * binder_get_node_from_ref() - get the node from the given proc/desc - * @proc: proc containing the ref - * @desc: the handle associated with the ref - * @need_strong_ref: if true, only return node if ref is strong - * @rdata: the id/refcount data for the ref - * - * Given a proc and ref handle, return the associated binder_node - * - * Return: a binder_node or NULL if not found or not strong when strong required - */ -static struct binder_node *binder_get_node_from_ref( - struct binder_proc *proc, - u32 desc, bool need_strong_ref, - struct binder_ref_data *rdata) -{ - struct binder_node *node; - struct binder_ref *ref; - - binder_proc_lock(proc); - ref = binder_get_ref_olocked(proc, desc, need_strong_ref); - if (!ref) - goto err_no_ref; - node = ref->node; - /* - * Take an implicit reference on the node to ensure - * it stays alive until the call to binder_put_node() - */ - binder_inc_node_tmpref(node); - if (rdata) - *rdata = ref->data; - binder_proc_unlock(proc); - - return node; - -err_no_ref: - binder_proc_unlock(proc); - return NULL; -} - -/** - * binder_free_ref() - free the binder_ref - * @ref: ref to free - * - * Free the binder_ref. Free the binder_node indicated by ref->node - * (if non-NULL) and the binder_ref_death indicated by ref->death. - */ -static void binder_free_ref(struct binder_ref *ref) -{ - if (ref->node) - binder_free_node(ref->node); - kfree(ref->death); - kfree(ref); -} - -/** - * binder_update_ref_for_handle() - inc/dec the ref for given handle - * @proc: proc containing the ref - * @desc: the handle associated with the ref - * @increment: true=inc reference, false=dec reference - * @strong: true=strong reference, false=weak reference - * @rdata: the id/refcount data for the ref - * - * Given a proc and ref handle, increment or decrement the ref - * according to "increment" arg. - * - * Return: 0 if successful, else errno - */ -static int binder_update_ref_for_handle(struct binder_proc *proc, - uint32_t desc, bool increment, bool strong, - struct binder_ref_data *rdata) -{ - int ret = 0; - struct binder_ref *ref; - bool delete_ref = false; - - binder_proc_lock(proc); - ref = binder_get_ref_olocked(proc, desc, strong); - if (!ref) { - ret = -EINVAL; - goto err_no_ref; - } - if (increment) - ret = binder_inc_ref_olocked(ref, strong, NULL); - else - delete_ref = binder_dec_ref_olocked(ref, strong); - - if (rdata) - *rdata = ref->data; - binder_proc_unlock(proc); - - if (delete_ref) - binder_free_ref(ref); - return ret; - -err_no_ref: - binder_proc_unlock(proc); - return ret; -} - -/** - * binder_dec_ref_for_handle() - dec the ref for given handle - * @proc: proc containing the ref - * @desc: the handle associated with the ref - * @strong: true=strong reference, false=weak reference - * @rdata: the id/refcount data for the ref - * - * Just calls binder_update_ref_for_handle() to decrement the ref. - * - * Return: 0 if successful, else errno - */ -static int binder_dec_ref_for_handle(struct binder_proc *proc, - uint32_t desc, bool strong, struct binder_ref_data *rdata) -{ - return binder_update_ref_for_handle(proc, desc, false, strong, rdata); -} - - -/** - * binder_inc_ref_for_node() - increment the ref for given proc/node - * @proc: proc containing the ref - * @node: target node - * @strong: true=strong reference, false=weak reference - * @target_list: worklist to use if node is incremented - * @rdata: the id/refcount data for the ref - * - * Given a proc and node, increment the ref. Create the ref if it - * doesn't already exist - * - * Return: 0 if successful, else errno - */ -static int binder_inc_ref_for_node(struct binder_proc *proc, - struct binder_node *node, - bool strong, - struct list_head *target_list, - struct binder_ref_data *rdata) -{ - struct binder_ref *ref; - struct binder_ref *new_ref = NULL; - int ret = 0; - - binder_proc_lock(proc); - ref = binder_get_ref_for_node_olocked(proc, node, NULL); - if (!ref) { - binder_proc_unlock(proc); - new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); - if (!new_ref) - return -ENOMEM; - binder_proc_lock(proc); - ref = binder_get_ref_for_node_olocked(proc, node, new_ref); - } - ret = binder_inc_ref_olocked(ref, strong, target_list); - *rdata = ref->data; - binder_proc_unlock(proc); - if (new_ref && ref != new_ref) - /* - * Another thread created the ref first so - * free the one we allocated - */ - kfree(new_ref); - return ret; -} - -static void binder_pop_transaction_ilocked(struct binder_thread *target_thread, - struct binder_transaction *t) -{ - BUG_ON(!target_thread); - BUG_ON(!spin_is_locked(&target_thread->proc->inner_lock)); - BUG_ON(target_thread->transaction_stack != t); - BUG_ON(target_thread->transaction_stack->from != target_thread); - target_thread->transaction_stack = - target_thread->transaction_stack->from_parent; - t->from = NULL; -} - -/** - * binder_thread_dec_tmpref() - decrement thread->tmp_ref - * @thread: thread to decrement - * - * A thread needs to be kept alive while being used to create or - * handle a transaction. binder_get_txn_from() is used to safely - * extract t->from from a binder_transaction and keep the thread - * indicated by t->from from being freed. When done with that - * binder_thread, this function is called to decrement the - * tmp_ref and free if appropriate (thread has been released - * and no transaction being processed by the driver) - */ -static void binder_thread_dec_tmpref(struct binder_thread *thread) -{ - /* - * atomic is used to protect the counter value while - * it cannot reach zero or thread->is_dead is false - */ - binder_inner_proc_lock(thread->proc); - atomic_dec(&thread->tmp_ref); - if (thread->is_dead && !atomic_read(&thread->tmp_ref)) { - binder_inner_proc_unlock(thread->proc); - binder_free_thread(thread); - return; - } - binder_inner_proc_unlock(thread->proc); -} - -/** - * binder_proc_dec_tmpref() - decrement proc->tmp_ref - * @proc: proc to decrement - * - * A binder_proc needs to be kept alive while being used to create or - * handle a transaction. proc->tmp_ref is incremented when - * creating a new transaction or the binder_proc is currently in-use - * by threads that are being released. When done with the binder_proc, - * this function is called to decrement the counter and free the - * proc if appropriate (proc has been released, all threads have - * been released and not currenly in-use to process a transaction). - */ -static void binder_proc_dec_tmpref(struct binder_proc *proc) -{ - binder_inner_proc_lock(proc); - proc->tmp_ref--; - if (proc->is_dead && RB_EMPTY_ROOT(&proc->threads) && - !proc->tmp_ref) { - binder_inner_proc_unlock(proc); - binder_free_proc(proc); - return; - } - binder_inner_proc_unlock(proc); -} - -/** - * binder_get_txn_from() - safely extract the "from" thread in transaction - * @t: binder transaction for t->from - * - * Atomically return the "from" thread and increment the tmp_ref - * count for the thread to ensure it stays alive until - * binder_thread_dec_tmpref() is called. - * - * Return: the value of t->from - */ -static struct binder_thread *binder_get_txn_from( - struct binder_transaction *t) -{ - struct binder_thread *from; - - spin_lock(&t->lock); - from = t->from; - if (from) - atomic_inc(&from->tmp_ref); - spin_unlock(&t->lock); - return from; + return ret; + } + ref->weak++; + } + return 0; } -/** - * binder_get_txn_from_and_acq_inner() - get t->from and acquire inner lock - * @t: binder transaction for t->from - * - * Same as binder_get_txn_from() except it also acquires the proc->inner_lock - * to guarantee that the thread cannot be released while operating on it. - * The caller must call binder_inner_proc_unlock() to release the inner lock - * as well as call binder_dec_thread_txn() to release the reference. - * - * Return: the value of t->from - */ -static struct binder_thread *binder_get_txn_from_and_acq_inner( - struct binder_transaction *t) + +static int binder_dec_ref(struct binder_ref *ref, int strong) { - struct binder_thread *from; + if (strong) { + if (ref->strong == 0) { + binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n", + ref->proc->pid, ref->debug_id, + ref->desc, ref->strong, ref->weak); + return -EINVAL; + } + ref->strong--; + if (ref->strong == 0) { + int ret; - from = binder_get_txn_from(t); - if (!from) - return NULL; - binder_inner_proc_lock(from->proc); - if (t->from) { - BUG_ON(from != t->from); - return from; + ret = binder_dec_node(ref->node, strong, 1); + if (ret) + return ret; + } + } else { + if (ref->weak == 0) { + binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n", + ref->proc->pid, ref->debug_id, + ref->desc, ref->strong, ref->weak); + return -EINVAL; + } + ref->weak--; } - binder_inner_proc_unlock(from->proc); - binder_thread_dec_tmpref(from); - return NULL; + if (ref->strong == 0 && ref->weak == 0) + binder_delete_ref(ref); + return 0; } -static void binder_free_transaction(struct binder_transaction *t) +static void binder_pop_transaction(struct binder_thread *target_thread, + struct binder_transaction *t) { + if (target_thread) { + BUG_ON(target_thread->transaction_stack != t); + BUG_ON(target_thread->transaction_stack->from != target_thread); + target_thread->transaction_stack = + target_thread->transaction_stack->from_parent; + t->from = NULL; + } + t->need_reply = 0; if (t->buffer) t->buffer->transaction = NULL; kfree(t); @@ -2058,28 +1329,30 @@ static void binder_send_failed_reply(struct binder_transaction *t, BUG_ON(t->flags & TF_ONE_WAY); while (1) { - target_thread = binder_get_txn_from_and_acq_inner(t); + target_thread = t->from; if (target_thread) { - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "send failed reply for transaction %d to %d:%d\n", - t->debug_id, - target_thread->proc->pid, - target_thread->pid); - - binder_pop_transaction_ilocked(target_thread, t); - if (target_thread->reply_error.cmd == BR_OK) { - target_thread->reply_error.cmd = error_code; - binder_enqueue_work_ilocked( - &target_thread->reply_error.work, - &target_thread->todo); + if (target_thread->return_error != BR_OK && + target_thread->return_error2 == BR_OK) { + target_thread->return_error2 = + target_thread->return_error; + target_thread->return_error = BR_OK; + } + if (target_thread->return_error == BR_OK) { + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "send failed reply for transaction %d to %d:%d\n", + t->debug_id, + target_thread->proc->pid, + target_thread->pid); + + binder_pop_transaction(target_thread, t); + target_thread->return_error = error_code; wake_up_interruptible(&target_thread->wait); } else { - WARN(1, "Unexpected reply error: %u\n", - target_thread->reply_error.cmd); + pr_err("reply failed, target thread, %d:%d, has error code %d already\n", + target_thread->proc->pid, + target_thread->pid, + target_thread->return_error); } - binder_inner_proc_unlock(target_thread->proc); - binder_thread_dec_tmpref(target_thread); - binder_free_transaction(t); return; } next = t->from_parent; @@ -2088,7 +1361,7 @@ static void binder_send_failed_reply(struct binder_transaction *t, "send failed reply for transaction %d, target dead\n", t->debug_id); - binder_free_transaction(t); + binder_pop_transaction(target_thread, t); if (next == NULL) { binder_debug(BINDER_DEBUG_DEAD_BINDER, "reply failed, no target thread at root\n"); @@ -2297,26 +1570,25 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, node->debug_id, (u64)node->ptr); binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER, 0); - binder_put_node(node); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct flat_binder_object *fp; - struct binder_ref_data rdata; - int ret; + struct binder_ref *ref; fp = to_flat_binder_object(hdr); - ret = binder_dec_ref_for_handle(proc, fp->handle, - hdr->type == BINDER_TYPE_HANDLE, &rdata); + ref = binder_get_ref(proc, fp->handle, + hdr->type == BINDER_TYPE_HANDLE); - if (ret) { - pr_err("transaction release %d bad handle %d, ret = %d\n", - debug_id, fp->handle, ret); + if (ref == NULL) { + pr_err("transaction release %d bad handle %d\n", + debug_id, fp->handle); break; } binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d\n", - rdata.debug_id, rdata.desc); + " ref %d desc %d (node %d)\n", + ref->debug_id, ref->desc, ref->node->debug_id); + binder_dec_ref(ref, hdr->type == BINDER_TYPE_HANDLE); } break; case BINDER_TYPE_FD: { @@ -2355,8 +1627,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, * back to kernel address space to access it */ parent_buffer = parent->buffer - - binder_alloc_get_user_buffer_offset( - &proc->alloc); + proc->user_buffer_offset; fd_buf_size = sizeof(u32) * fda->num_fds; if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { @@ -2388,122 +1659,102 @@ static int binder_translate_binder(struct flat_binder_object *fp, struct binder_thread *thread) { struct binder_node *node; + struct binder_ref *ref; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; - struct binder_ref_data rdata; - int ret = 0; node = binder_get_node(proc, fp->binder); if (!node) { - node = binder_new_node(proc, fp); + node = binder_new_node(proc, fp->binder, fp->cookie); if (!node) return -ENOMEM; + + node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK; + node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, (u64)fp->binder, node->debug_id, (u64)fp->cookie, (u64)node->cookie); - ret = -EINVAL; - goto done; - } - if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { - ret = -EPERM; - goto done; + return -EINVAL; } + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) + return -EPERM; - ret = binder_inc_ref_for_node(target_proc, node, - fp->hdr.type == BINDER_TYPE_BINDER, - &thread->todo, &rdata); - if (ret) - goto done; + ref = binder_get_ref_for_node(target_proc, node); + if (!ref) + return -EINVAL; if (fp->hdr.type == BINDER_TYPE_BINDER) fp->hdr.type = BINDER_TYPE_HANDLE; else fp->hdr.type = BINDER_TYPE_WEAK_HANDLE; fp->binder = 0; - fp->handle = rdata.desc; + fp->handle = ref->desc; fp->cookie = 0; + binder_inc_ref(ref, fp->hdr.type == BINDER_TYPE_HANDLE, &thread->todo); - trace_binder_transaction_node_to_ref(t, node, &rdata); + trace_binder_transaction_node_to_ref(t, node, ref); binder_debug(BINDER_DEBUG_TRANSACTION, " node %d u%016llx -> ref %d desc %d\n", node->debug_id, (u64)node->ptr, - rdata.debug_id, rdata.desc); -done: - binder_put_node(node); - return ret; + ref->debug_id, ref->desc); + + return 0; } static int binder_translate_handle(struct flat_binder_object *fp, struct binder_transaction *t, struct binder_thread *thread) { + struct binder_ref *ref; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; - struct binder_node *node; - struct binder_ref_data src_rdata; - int ret = 0; - node = binder_get_node_from_ref(proc, fp->handle, - fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata); - if (!node) { + ref = binder_get_ref(proc, fp->handle, + fp->hdr.type == BINDER_TYPE_HANDLE); + if (!ref) { binder_user_error("%d:%d got transaction with invalid handle, %d\n", proc->pid, thread->pid, fp->handle); return -EINVAL; } - if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { - ret = -EPERM; - goto done; - } + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) + return -EPERM; - binder_node_lock(node); - if (node->proc == target_proc) { + if (ref->node->proc == target_proc) { if (fp->hdr.type == BINDER_TYPE_HANDLE) fp->hdr.type = BINDER_TYPE_BINDER; else fp->hdr.type = BINDER_TYPE_WEAK_BINDER; - fp->binder = node->ptr; - fp->cookie = node->cookie; - if (node->proc) - binder_inner_proc_lock(node->proc); - binder_inc_node_nilocked(node, - fp->hdr.type == BINDER_TYPE_BINDER, - 0, NULL); - if (node->proc) - binder_inner_proc_unlock(node->proc); - trace_binder_transaction_ref_to_node(t, node, &src_rdata); + fp->binder = ref->node->ptr; + fp->cookie = ref->node->cookie; + binder_inc_node(ref->node, fp->hdr.type == BINDER_TYPE_BINDER, + 0, NULL); + trace_binder_transaction_ref_to_node(t, ref); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> node %d u%016llx\n", - src_rdata.debug_id, src_rdata.desc, node->debug_id, - (u64)node->ptr); - binder_node_unlock(node); + ref->debug_id, ref->desc, ref->node->debug_id, + (u64)ref->node->ptr); } else { - int ret; - struct binder_ref_data dest_rdata; + struct binder_ref *new_ref; - binder_node_unlock(node); - ret = binder_inc_ref_for_node(target_proc, node, - fp->hdr.type == BINDER_TYPE_HANDLE, - NULL, &dest_rdata); - if (ret) - goto done; + new_ref = binder_get_ref_for_node(target_proc, ref->node); + if (!new_ref) + return -EINVAL; fp->binder = 0; - fp->handle = dest_rdata.desc; + fp->handle = new_ref->desc; fp->cookie = 0; - trace_binder_transaction_ref_to_ref(t, node, &src_rdata, - &dest_rdata); + binder_inc_ref(new_ref, fp->hdr.type == BINDER_TYPE_HANDLE, + NULL); + trace_binder_transaction_ref_to_ref(t, ref, new_ref); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> ref %d desc %d (node %d)\n", - src_rdata.debug_id, src_rdata.desc, - dest_rdata.debug_id, dest_rdata.desc, - node->debug_id); + ref->debug_id, ref->desc, new_ref->debug_id, + new_ref->desc, ref->node->debug_id); } -done: - binder_put_node(node); - return ret; + return 0; } static int binder_translate_fd(int fd, @@ -2594,8 +1845,7 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda, * Since the parent was already fixed up, convert it * back to the kernel address space to access it */ - parent_buffer = parent->buffer - - binder_alloc_get_user_buffer_offset(&target_proc->alloc); + parent_buffer = parent->buffer - target_proc->user_buffer_offset; fd_array = (u32 *)(parent_buffer + fda->parent_offset); if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) { binder_user_error("%d:%d parent offset not aligned correctly.\n", @@ -2663,87 +1913,12 @@ static int binder_fixup_parent(struct binder_transaction *t, return -EINVAL; } parent_buffer = (u8 *)(parent->buffer - - binder_alloc_get_user_buffer_offset( - &target_proc->alloc)); + target_proc->user_buffer_offset); *(binder_uintptr_t *)(parent_buffer + bp->parent_offset) = bp->buffer; return 0; } -/** - * binder_proc_transaction() - sends a transaction to a process and wakes it up - * @t: transaction to send - * @proc: process to send the transaction to - * @thread: thread in @proc to send the transaction to (may be NULL) - * - * This function queues a transaction to the specified process. It will try - * to find a thread in the target process to handle the transaction and - * wake it up. If no thread is found, the work is queued to the proc - * waitqueue. - * - * If the @thread parameter is not NULL, the transaction is always queued - * to the waitlist of that specific thread. - * - * Return: true if the transactions was successfully queued - * false if the target process or thread is dead - */ -static bool binder_proc_transaction(struct binder_transaction *t, - struct binder_proc *proc, - struct binder_thread *thread) -{ - struct list_head *target_list = NULL; - struct binder_node *node = t->buffer->target_node; - struct binder_priority node_prio; - bool oneway = !!(t->flags & TF_ONE_WAY); - bool wakeup = true; - - BUG_ON(!node); - binder_node_lock(node); - node_prio.prio = node->min_priority; - node_prio.sched_policy = node->sched_policy; - - if (oneway) { - BUG_ON(thread); - if (node->has_async_transaction) { - target_list = &node->async_todo; - wakeup = false; - } else { - node->has_async_transaction = 1; - } - } - - binder_inner_proc_lock(proc); - - if (proc->is_dead || (thread && thread->is_dead)) { - binder_inner_proc_unlock(proc); - binder_node_unlock(node); - return false; - } - - if (!thread && !target_list) - thread = binder_select_thread_ilocked(proc); - - if (thread) { - target_list = &thread->todo; - binder_transaction_priority(thread->task, t, node_prio, - node->inherit_rt); - } else if (!target_list) { - target_list = &proc->todo; - } else { - BUG_ON(target_list != &node->async_todo); - } - - binder_enqueue_work_ilocked(&t->work, target_list); - - if (wakeup) - binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); - - binder_inner_proc_unlock(proc); - binder_node_unlock(node); - - return true; -} - static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply, @@ -2755,21 +1930,19 @@ static void binder_transaction(struct binder_proc *proc, binder_size_t *offp, *off_end, *off_start; binder_size_t off_min; u8 *sg_bufp, *sg_buf_end; - struct binder_proc *target_proc = NULL; + struct binder_proc *target_proc; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; + struct list_head *target_list; + wait_queue_head_t *target_wait; struct binder_transaction *in_reply_to = NULL; struct binder_transaction_log_entry *e; - uint32_t return_error = 0; - uint32_t return_error_param = 0; - uint32_t return_error_line = 0; + uint32_t return_error; struct binder_buffer_object *last_fixup_obj = NULL; binder_size_t last_fixup_min_off = 0; struct binder_context *context = proc->context; - int t_debug_id = atomic_inc_return(&binder_last_id); - e = binder_transaction_log_add(&binder_transaction_log); - e->debug_id = t_debug_id; + e = binder_transaction_log_add(&context->transaction_log); e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); e->from_proc = proc->pid; e->from_thread = thread->pid; @@ -2779,39 +1952,29 @@ static void binder_transaction(struct binder_proc *proc, e->context_name = proc->context->name; if (reply) { - binder_inner_proc_lock(proc); in_reply_to = thread->transaction_stack; if (in_reply_to == NULL) { - binder_inner_proc_unlock(proc); binder_user_error("%d:%d got reply transaction with no transaction stack\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - return_error_param = -EPROTO; - return_error_line = __LINE__; goto err_empty_call_stack; } + binder_set_nice(in_reply_to->saved_priority); if (in_reply_to->to_thread != thread) { - spin_lock(&in_reply_to->lock); binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, in_reply_to->debug_id, in_reply_to->to_proc ? in_reply_to->to_proc->pid : 0, in_reply_to->to_thread ? in_reply_to->to_thread->pid : 0); - spin_unlock(&in_reply_to->lock); - binder_inner_proc_unlock(proc); return_error = BR_FAILED_REPLY; - return_error_param = -EPROTO; - return_error_line = __LINE__; in_reply_to = NULL; goto err_bad_call_stack; } thread->transaction_stack = in_reply_to->to_parent; - binder_inner_proc_unlock(proc); - target_thread = binder_get_txn_from_and_acq_inner(in_reply_to); + target_thread = in_reply_to->from; if (target_thread == NULL) { return_error = BR_DEAD_REPLY; - return_error_line = __LINE__; goto err_dead_binder; } if (target_thread->transaction_stack != in_reply_to) { @@ -2820,137 +1983,89 @@ static void binder_transaction(struct binder_proc *proc, target_thread->transaction_stack ? target_thread->transaction_stack->debug_id : 0, in_reply_to->debug_id); - binder_inner_proc_unlock(target_thread->proc); return_error = BR_FAILED_REPLY; - return_error_param = -EPROTO; - return_error_line = __LINE__; in_reply_to = NULL; target_thread = NULL; goto err_dead_binder; } target_proc = target_thread->proc; - target_proc->tmp_ref++; - binder_inner_proc_unlock(target_thread->proc); } else { if (tr->target.handle) { struct binder_ref *ref; - /* - * There must already be a strong ref - * on this node. If so, do a strong - * increment on the node to ensure it - * stays alive until the transaction is - * done. - */ - binder_proc_lock(proc); - ref = binder_get_ref_olocked(proc, tr->target.handle, - true); - if (ref) { - binder_inc_node(ref->node, 1, 0, NULL); - target_node = ref->node; - } - binder_proc_unlock(proc); - if (target_node == NULL) { + ref = binder_get_ref(proc, tr->target.handle, true); + if (ref == NULL) { binder_user_error("%d:%d got transaction to invalid handle\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - return_error_param = -EINVAL; - return_error_line = __LINE__; goto err_invalid_target_handle; } + target_node = ref->node; } else { - mutex_lock(&context->context_mgr_node_lock); target_node = context->binder_context_mgr_node; if (target_node == NULL) { return_error = BR_DEAD_REPLY; - mutex_unlock(&context->context_mgr_node_lock); - return_error_line = __LINE__; goto err_no_context_mgr_node; } - binder_inc_node(target_node, 1, 0, NULL); - mutex_unlock(&context->context_mgr_node_lock); } e->to_node = target_node->debug_id; - binder_node_lock(target_node); target_proc = target_node->proc; if (target_proc == NULL) { - binder_node_unlock(target_node); return_error = BR_DEAD_REPLY; - return_error_line = __LINE__; goto err_dead_binder; } - binder_inner_proc_lock(target_proc); - target_proc->tmp_ref++; - binder_inner_proc_unlock(target_proc); - binder_node_unlock(target_node); if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) { return_error = BR_FAILED_REPLY; - return_error_param = -EPERM; - return_error_line = __LINE__; goto err_invalid_target_handle; } - binder_inner_proc_lock(proc); if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; tmp = thread->transaction_stack; if (tmp->to_thread != thread) { - spin_lock(&tmp->lock); binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, tmp->debug_id, tmp->to_proc ? tmp->to_proc->pid : 0, tmp->to_thread ? tmp->to_thread->pid : 0); - spin_unlock(&tmp->lock); - binder_inner_proc_unlock(proc); return_error = BR_FAILED_REPLY; - return_error_param = -EPROTO; - return_error_line = __LINE__; goto err_bad_call_stack; } while (tmp) { - struct binder_thread *from; - - spin_lock(&tmp->lock); - from = tmp->from; - if (from && from->proc == target_proc) { - atomic_inc(&from->tmp_ref); - target_thread = from; - spin_unlock(&tmp->lock); - break; - } - spin_unlock(&tmp->lock); + if (tmp->from && tmp->from->proc == target_proc) + target_thread = tmp->from; tmp = tmp->from_parent; } } - binder_inner_proc_unlock(proc); } - if (target_thread) + if (target_thread) { e->to_thread = target_thread->pid; + target_list = &target_thread->todo; + target_wait = &target_thread->wait; + } else { + target_list = &target_proc->todo; + target_wait = &target_proc->wait; + } e->to_proc = target_proc->pid; /* TODO: reuse incoming transaction for reply */ - t = kzalloc(sizeof(*t), GFP_KERNEL); + t = kzalloc_preempt_disabled(sizeof(*t)); if (t == NULL) { return_error = BR_FAILED_REPLY; - return_error_param = -ENOMEM; - return_error_line = __LINE__; goto err_alloc_t_failed; } binder_stats_created(BINDER_STAT_TRANSACTION); - spin_lock_init(&t->lock); - tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); + tcomplete = kzalloc_preempt_disabled(sizeof(*tcomplete)); if (tcomplete == NULL) { return_error = BR_FAILED_REPLY; - return_error_param = -ENOMEM; - return_error_line = __LINE__; goto err_alloc_tcomplete_failed; } binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); - t->debug_id = t_debug_id; + t->debug_id = atomic_inc_return(&binder_last_id); + e->debug_id = t->debug_id; if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, @@ -2980,30 +2095,15 @@ static void binder_transaction(struct binder_proc *proc, t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; - if (!(t->flags & TF_ONE_WAY) && - binder_supported_policy(current->policy)) { - /* Inherit supported policies for synchronous transactions */ - t->priority.sched_policy = current->policy; - t->priority.prio = current->normal_prio; - } else { - /* Otherwise, fall back to the default priority */ - t->priority = target_proc->default_priority; - } + t->priority = task_nice(current); trace_binder_transaction(reply, t, target_node); - t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, + t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, extra_buffers_size, !reply && (t->flags & TF_ONE_WAY)); - if (IS_ERR(t->buffer)) { - /* - * -ESRCH indicates VMA cleared. The target is dying. - */ - return_error_param = PTR_ERR(t->buffer); - return_error = return_error_param == -ESRCH ? - BR_DEAD_REPLY : BR_FAILED_REPLY; - return_error_line = __LINE__; - t->buffer = NULL; + if (t->buffer == NULL) { + return_error = BR_FAILED_REPLY; goto err_binder_alloc_buf_failed; } t->buffer->allow_user_free = 0; @@ -3011,34 +2111,31 @@ static void binder_transaction(struct binder_proc *proc, t->buffer->transaction = t; t->buffer->target_node = target_node; trace_binder_transaction_alloc_buf(t->buffer); + if (target_node) + binder_inc_node(target_node, 1, 0, NULL); + off_start = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); offp = off_start; - if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) + if (copy_from_user_preempt_disabled(t->buffer->data, (const void __user *)(uintptr_t) tr->data.ptr.buffer, tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - return_error_param = -EFAULT; - return_error_line = __LINE__; goto err_copy_data_failed; } - if (copy_from_user(offp, (const void __user *)(uintptr_t) + if (copy_from_user_preempt_disabled(offp, (const void __user *)(uintptr_t) tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - return_error_param = -EFAULT; - return_error_line = __LINE__; goto err_copy_data_failed; } if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", proc->pid, thread->pid, (u64)tr->offsets_size); return_error = BR_FAILED_REPLY; - return_error_param = -EINVAL; - return_error_line = __LINE__; goto err_bad_offset; } if (!IS_ALIGNED(extra_buffers_size, sizeof(u64))) { @@ -3046,8 +2143,6 @@ static void binder_transaction(struct binder_proc *proc, proc->pid, thread->pid, (u64)extra_buffers_size); return_error = BR_FAILED_REPLY; - return_error_param = -EINVAL; - return_error_line = __LINE__; goto err_bad_offset; } off_end = (void *)off_start + tr->offsets_size; @@ -3064,8 +2159,6 @@ static void binder_transaction(struct binder_proc *proc, (u64)off_min, (u64)t->buffer->data_size); return_error = BR_FAILED_REPLY; - return_error_param = -EINVAL; - return_error_line = __LINE__; goto err_bad_offset; } @@ -3080,8 +2173,6 @@ static void binder_transaction(struct binder_proc *proc, ret = binder_translate_binder(fp, t, thread); if (ret < 0) { return_error = BR_FAILED_REPLY; - return_error_param = ret; - return_error_line = __LINE__; goto err_translate_failed; } } break; @@ -3093,8 +2184,6 @@ static void binder_transaction(struct binder_proc *proc, ret = binder_translate_handle(fp, t, thread); if (ret < 0) { return_error = BR_FAILED_REPLY; - return_error_param = ret; - return_error_line = __LINE__; goto err_translate_failed; } } break; @@ -3106,8 +2195,6 @@ static void binder_transaction(struct binder_proc *proc, if (target_fd < 0) { return_error = BR_FAILED_REPLY; - return_error_param = target_fd; - return_error_line = __LINE__; goto err_translate_failed; } fp->pad_binder = 0; @@ -3124,8 +2211,6 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with invalid parent offset or type\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - return_error_param = -EINVAL; - return_error_line = __LINE__; goto err_bad_parent; } if (!binder_validate_fixup(t->buffer, off_start, @@ -3135,16 +2220,12 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - return_error_param = -EINVAL; - return_error_line = __LINE__; goto err_bad_parent; } ret = binder_translate_fd_array(fda, parent, t, thread, in_reply_to); if (ret < 0) { return_error = BR_FAILED_REPLY; - return_error_param = ret; - return_error_line = __LINE__; goto err_translate_failed; } last_fixup_obj = parent; @@ -3160,24 +2241,20 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with too large buffer\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - return_error_param = -EINVAL; - return_error_line = __LINE__; goto err_bad_offset; } - if (copy_from_user(sg_bufp, - (const void __user *)(uintptr_t) - bp->buffer, bp->length)) { + if (copy_from_user_preempt_disabled( + sg_bufp, + (const void __user *)(uintptr_t) + bp->buffer, bp->length)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); - return_error_param = -EFAULT; return_error = BR_FAILED_REPLY; - return_error_line = __LINE__; goto err_copy_data_failed; } /* Fixup buffer pointer to target proc address space */ bp->buffer = (uintptr_t)sg_bufp + - binder_alloc_get_user_buffer_offset( - &target_proc->alloc); + target_proc->user_buffer_offset; sg_bufp += ALIGN(bp->length, sizeof(u64)); ret = binder_fixup_parent(t, thread, bp, off_start, @@ -3186,8 +2263,6 @@ static void binder_transaction(struct binder_proc *proc, last_fixup_min_off); if (ret < 0) { return_error = BR_FAILED_REPLY; - return_error_param = ret; - return_error_line = __LINE__; goto err_translate_failed; } last_fixup_obj = bp; @@ -3197,62 +2272,42 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with invalid object type, %x\n", proc->pid, thread->pid, hdr->type); return_error = BR_FAILED_REPLY; - return_error_param = -EINVAL; - return_error_line = __LINE__; goto err_bad_object_type; } } - tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; - binder_enqueue_work(proc, tcomplete, &thread->todo); - t->work.type = BINDER_WORK_TRANSACTION; - if (reply) { - binder_inner_proc_lock(target_proc); - if (target_thread->is_dead) { - binder_inner_proc_unlock(target_proc); - goto err_dead_proc_or_thread; - } BUG_ON(t->buffer->async_transaction != 0); - binder_pop_transaction_ilocked(target_thread, in_reply_to); - binder_enqueue_work_ilocked(&t->work, &target_thread->todo); - binder_inner_proc_unlock(target_proc); - wake_up_interruptible_sync(&target_thread->wait); - binder_restore_priority(current, in_reply_to->saved_priority); - binder_free_transaction(in_reply_to); + binder_pop_transaction(target_thread, in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { BUG_ON(t->buffer->async_transaction != 0); - binder_inner_proc_lock(proc); t->need_reply = 1; t->from_parent = thread->transaction_stack; thread->transaction_stack = t; - binder_inner_proc_unlock(proc); - if (!binder_proc_transaction(t, target_proc, target_thread)) { - binder_inner_proc_lock(proc); - binder_pop_transaction_ilocked(thread, t); - binder_inner_proc_unlock(proc); - goto err_dead_proc_or_thread; - } } else { BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); - if (!binder_proc_transaction(t, target_proc, NULL)) - goto err_dead_proc_or_thread; + if (target_node->has_async_transaction) { + target_list = &target_node->async_todo; + target_wait = NULL; + } else + target_node->has_async_transaction = 1; + } + t->work.type = BINDER_WORK_TRANSACTION; + list_add_tail(&t->work.entry, target_list); + tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; + list_add_tail(&tcomplete->entry, &thread->todo); + if (target_wait) { + if (reply || !(t->flags & TF_ONE_WAY)) { + preempt_disable(); + wake_up_interruptible_sync(target_wait); + preempt_enable_no_resched(); + } + else { + wake_up_interruptible(target_wait); + } } - if (target_thread) - binder_thread_dec_tmpref(target_thread); - binder_proc_dec_tmpref(target_proc); - /* - * write barrier to synchronize with initialization - * of log entry - */ - smp_wmb(); - WRITE_ONCE(e->debug_id_done, t_debug_id); return; -err_dead_proc_or_thread: - return_error = BR_DEAD_REPLY; - return_error_line = __LINE__; - binder_dequeue_work(proc, tcomplete); err_translate_failed: err_bad_object_type: err_bad_offset: @@ -3260,9 +2315,8 @@ err_bad_parent: err_copy_data_failed: trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); - target_node = NULL; t->buffer->transaction = NULL; - binder_alloc_free_buf(&target_proc->alloc, t->buffer); + binder_free_buf(target_proc, t->buffer); err_binder_alloc_buf_failed: kfree(tcomplete); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); @@ -3275,50 +2329,25 @@ err_empty_call_stack: err_dead_binder: err_invalid_target_handle: err_no_context_mgr_node: - if (target_thread) - binder_thread_dec_tmpref(target_thread); - if (target_proc) - binder_proc_dec_tmpref(target_proc); - if (target_node) - binder_dec_node(target_node, 1, 0); - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d transaction failed %d/%d, size %lld-%lld line %d\n", - proc->pid, thread->pid, return_error, return_error_param, - (u64)tr->data_size, (u64)tr->offsets_size, - return_error_line); + "%d:%d transaction failed %d, size %lld-%lld\n", + proc->pid, thread->pid, return_error, + (u64)tr->data_size, (u64)tr->offsets_size); { struct binder_transaction_log_entry *fe; - e->return_error = return_error; - e->return_error_param = return_error_param; - e->return_error_line = return_error_line; - fe = binder_transaction_log_add(&binder_transaction_log_failed); + fe = binder_transaction_log_add( + &context->transaction_log_failed); *fe = *e; - /* - * write barrier to synchronize with initialization - * of log entry - */ - smp_wmb(); - WRITE_ONCE(e->debug_id_done, t_debug_id); - WRITE_ONCE(fe->debug_id_done, t_debug_id); } - BUG_ON(thread->return_error.cmd != BR_OK); + BUG_ON(thread->return_error != BR_OK); if (in_reply_to) { - binder_restore_priority(current, in_reply_to->saved_priority); - thread->return_error.cmd = BR_TRANSACTION_COMPLETE; - binder_enqueue_work(thread->proc, - &thread->return_error.work, - &thread->todo); + thread->return_error = BR_TRANSACTION_COMPLETE; binder_send_failed_reply(in_reply_to, return_error); - } else { - thread->return_error.cmd = return_error; - binder_enqueue_work(thread->proc, - &thread->return_error.work, - &thread->todo); - } + } else + thread->return_error = return_error; } static int binder_thread_write(struct binder_proc *proc, @@ -3332,17 +2361,15 @@ static int binder_thread_write(struct binder_proc *proc, void __user *ptr = buffer + *consumed; void __user *end = buffer + size; - while (ptr < end && thread->return_error.cmd == BR_OK) { - int ret; - - if (get_user(cmd, (uint32_t __user *)ptr)) + while (ptr < end && thread->return_error == BR_OK) { + if (get_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); trace_binder_command(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { - atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]); - atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]); - atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]); + if (_IOC_NR(cmd) < ARRAY_SIZE(context->binder_stats.bc)) { + context->binder_stats.bc[_IOC_NR(cmd)]++; + proc->stats.bc[_IOC_NR(cmd)]++; + thread->stats.bc[_IOC_NR(cmd)]++; } switch (cmd) { case BC_INCREFS: @@ -3350,61 +2377,53 @@ static int binder_thread_write(struct binder_proc *proc, case BC_RELEASE: case BC_DECREFS: { uint32_t target; + struct binder_ref *ref; const char *debug_string; - bool strong = cmd == BC_ACQUIRE || cmd == BC_RELEASE; - bool increment = cmd == BC_INCREFS || cmd == BC_ACQUIRE; - struct binder_ref_data rdata; - if (get_user(target, (uint32_t __user *)ptr)) + if (get_user_preempt_disabled(target, (uint32_t __user *)ptr)) return -EFAULT; - ptr += sizeof(uint32_t); - ret = -1; - if (increment && !target) { - struct binder_node *ctx_mgr_node; - mutex_lock(&context->context_mgr_node_lock); - ctx_mgr_node = context->binder_context_mgr_node; - if (ctx_mgr_node) - ret = binder_inc_ref_for_node( - proc, ctx_mgr_node, - strong, NULL, &rdata); - mutex_unlock(&context->context_mgr_node_lock); - } - if (ret) - ret = binder_update_ref_for_handle( - proc, target, increment, strong, - &rdata); - if (!ret && rdata.desc != target) { - binder_user_error("%d:%d tried to acquire reference to desc %d, got %d instead\n", - proc->pid, thread->pid, - target, rdata.desc); + if (target == 0 && context->binder_context_mgr_node && + (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) { + ref = binder_get_ref_for_node(proc, + context->binder_context_mgr_node); + if (ref->desc != target) { + binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n", + proc->pid, thread->pid, + ref->desc); + } + } else + ref = binder_get_ref(proc, target, + cmd == BC_ACQUIRE || + cmd == BC_RELEASE); + if (ref == NULL) { + binder_user_error("%d:%d refcount change on invalid ref %d\n", + proc->pid, thread->pid, target); + break; } switch (cmd) { case BC_INCREFS: debug_string = "IncRefs"; + binder_inc_ref(ref, 0, NULL); break; case BC_ACQUIRE: debug_string = "Acquire"; + binder_inc_ref(ref, 1, NULL); break; case BC_RELEASE: debug_string = "Release"; + binder_dec_ref(ref, 1); break; case BC_DECREFS: default: debug_string = "DecRefs"; - break; - } - if (ret) { - binder_user_error("%d:%d %s %d refcount change on invalid ref %d ret %d\n", - proc->pid, thread->pid, debug_string, - strong, target, ret); + binder_dec_ref(ref, 0); break; } binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s ref %d desc %d s %d w %d\n", - proc->pid, thread->pid, debug_string, - rdata.debug_id, rdata.desc, rdata.strong, - rdata.weak); + "%d:%d %s ref %d desc %d s %d w %d for node %d\n", + proc->pid, thread->pid, debug_string, ref->debug_id, + ref->desc, ref->strong, ref->weak, ref->node->debug_id); break; } case BC_INCREFS_DONE: @@ -3412,12 +2431,11 @@ static int binder_thread_write(struct binder_proc *proc, binder_uintptr_t node_ptr; binder_uintptr_t cookie; struct binder_node *node; - bool free_node; - if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) + if (get_user_preempt_disabled(node_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - if (get_user(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); node = binder_get_node(proc, node_ptr); @@ -3437,17 +2455,13 @@ static int binder_thread_write(struct binder_proc *proc, "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", (u64)node_ptr, node->debug_id, (u64)cookie, (u64)node->cookie); - binder_put_node(node); break; } - binder_node_inner_lock(node); if (cmd == BC_ACQUIRE_DONE) { if (node->pending_strong_ref == 0) { binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", proc->pid, thread->pid, node->debug_id); - binder_node_inner_unlock(node); - binder_put_node(node); break; } node->pending_strong_ref = 0; @@ -3456,23 +2470,16 @@ static int binder_thread_write(struct binder_proc *proc, binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", proc->pid, thread->pid, node->debug_id); - binder_node_inner_unlock(node); - binder_put_node(node); break; } node->pending_weak_ref = 0; } - free_node = binder_dec_node_nilocked(node, - cmd == BC_ACQUIRE_DONE, 0); - WARN_ON(free_node); + binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s node %d ls %d lw %d tr %d\n", + "%d:%d %s node %d ls %d lw %d\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node->debug_id, node->local_strong_refs, - node->local_weak_refs, node->tmp_refs); - binder_node_inner_unlock(node); - binder_put_node(node); + node->debug_id, node->local_strong_refs, node->local_weak_refs); break; } case BC_ATTEMPT_ACQUIRE: @@ -3486,12 +2493,11 @@ static int binder_thread_write(struct binder_proc *proc, binder_uintptr_t data_ptr; struct binder_buffer *buffer; - if (get_user(data_ptr, (binder_uintptr_t __user *)ptr)) + if (get_user_preempt_disabled(data_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - buffer = binder_alloc_prepare_to_free(&proc->alloc, - data_ptr); + buffer = binder_buffer_lookup(proc, data_ptr); if (buffer == NULL) { binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", proc->pid, thread->pid, (u64)data_ptr); @@ -3513,25 +2519,15 @@ static int binder_thread_write(struct binder_proc *proc, buffer->transaction = NULL; } if (buffer->async_transaction && buffer->target_node) { - struct binder_node *buf_node; - struct binder_work *w; - - buf_node = buffer->target_node; - binder_node_inner_lock(buf_node); - BUG_ON(!buf_node->has_async_transaction); - BUG_ON(buf_node->proc != proc); - w = binder_dequeue_work_head_ilocked( - &buf_node->async_todo); - if (!w) - buf_node->has_async_transaction = 0; + BUG_ON(!buffer->target_node->has_async_transaction); + if (list_empty(&buffer->target_node->async_todo)) + buffer->target_node->has_async_transaction = 0; else - binder_enqueue_work_ilocked( - w, &thread->todo); - binder_node_inner_unlock(buf_node); + list_move_tail(buffer->target_node->async_todo.next, &thread->todo); } trace_binder_transaction_buffer_release(buffer); binder_transaction_buffer_release(proc, buffer, NULL); - binder_alloc_free_buf(&proc->alloc, buffer); + binder_free_buf(proc, buffer); break; } @@ -3539,7 +2535,8 @@ static int binder_thread_write(struct binder_proc *proc, case BC_REPLY_SG: { struct binder_transaction_data_sg tr; - if (copy_from_user(&tr, ptr, sizeof(tr))) + if (copy_from_user_preempt_disabled(&tr, ptr, + sizeof(tr))) return -EFAULT; ptr += sizeof(tr); binder_transaction(proc, thread, &tr.transaction_data, @@ -3550,7 +2547,7 @@ static int binder_thread_write(struct binder_proc *proc, case BC_REPLY: { struct binder_transaction_data tr; - if (copy_from_user(&tr, ptr, sizeof(tr))) + if (copy_from_user_preempt_disabled(&tr, ptr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr); binder_transaction(proc, thread, &tr, @@ -3562,7 +2559,6 @@ static int binder_thread_write(struct binder_proc *proc, binder_debug(BINDER_DEBUG_THREADS, "%d:%d BC_REGISTER_LOOPER\n", proc->pid, thread->pid); - binder_inner_proc_lock(proc); if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n", @@ -3576,7 +2572,6 @@ static int binder_thread_write(struct binder_proc *proc, proc->requested_threads_started++; } thread->looper |= BINDER_LOOPER_STATE_REGISTERED; - binder_inner_proc_unlock(proc); break; case BC_ENTER_LOOPER: binder_debug(BINDER_DEBUG_THREADS, @@ -3601,37 +2596,15 @@ static int binder_thread_write(struct binder_proc *proc, uint32_t target; binder_uintptr_t cookie; struct binder_ref *ref; - struct binder_ref_death *death = NULL; + struct binder_ref_death *death; - if (get_user(target, (uint32_t __user *)ptr)) + if (get_user_preempt_disabled(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (get_user(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { - /* - * Allocate memory for death notification - * before taking lock - */ - death = kzalloc(sizeof(*death), GFP_KERNEL); - if (death == NULL) { - WARN_ON(thread->return_error.cmd != - BR_OK); - thread->return_error.cmd = BR_ERROR; - binder_enqueue_work( - thread->proc, - &thread->return_error.work, - &thread->todo); - binder_debug( - BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", - proc->pid, thread->pid); - break; - } - } - binder_proc_lock(proc); - ref = binder_get_ref_olocked(proc, target, false); + ref = binder_get_ref(proc, target, false); if (ref == NULL) { binder_user_error("%d:%d %s invalid ref %d\n", proc->pid, thread->pid, @@ -3639,8 +2612,6 @@ static int binder_thread_write(struct binder_proc *proc, "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", target); - binder_proc_unlock(proc); - kfree(death); break; } @@ -3650,18 +2621,21 @@ static int binder_thread_write(struct binder_proc *proc, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", - (u64)cookie, ref->data.debug_id, - ref->data.desc, ref->data.strong, - ref->data.weak, ref->node->debug_id); + (u64)cookie, ref->debug_id, ref->desc, + ref->strong, ref->weak, ref->node->debug_id); - binder_node_lock(ref->node); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { if (ref->death) { binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n", proc->pid, thread->pid); - binder_node_unlock(ref->node); - binder_proc_unlock(proc); - kfree(death); + break; + } + death = kzalloc_preempt_disabled(sizeof(*death)); + if (death == NULL) { + thread->return_error = BR_ERROR; + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", + proc->pid, thread->pid); break; } binder_stats_created(BINDER_STAT_DEATH); @@ -3670,29 +2644,17 @@ static int binder_thread_write(struct binder_proc *proc, ref->death = death; if (ref->node->proc == NULL) { ref->death->work.type = BINDER_WORK_DEAD_BINDER; - if (thread->looper & - (BINDER_LOOPER_STATE_REGISTERED | - BINDER_LOOPER_STATE_ENTERED)) - binder_enqueue_work( - proc, - &ref->death->work, - &thread->todo); - else { - binder_inner_proc_lock(proc); - binder_enqueue_work_ilocked( - &ref->death->work, - &proc->todo); - binder_wakeup_proc_ilocked( - proc); - binder_inner_proc_unlock(proc); + if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { + list_add_tail(&ref->death->work.entry, &thread->todo); + } else { + list_add_tail(&ref->death->work.entry, &proc->todo); + wake_up_interruptible(&proc->wait); } } } else { if (ref->death == NULL) { binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n", proc->pid, thread->pid); - binder_node_unlock(ref->node); - binder_proc_unlock(proc); break; } death = ref->death; @@ -3701,52 +2663,33 @@ static int binder_thread_write(struct binder_proc *proc, proc->pid, thread->pid, (u64)death->cookie, (u64)cookie); - binder_node_unlock(ref->node); - binder_proc_unlock(proc); break; } ref->death = NULL; - binder_inner_proc_lock(proc); if (list_empty(&death->work.entry)) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & - (BINDER_LOOPER_STATE_REGISTERED | - BINDER_LOOPER_STATE_ENTERED)) - binder_enqueue_work_ilocked( - &death->work, - &thread->todo); - else { - binder_enqueue_work_ilocked( - &death->work, - &proc->todo); - binder_wakeup_proc_ilocked( - proc); + if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { + list_add_tail(&death->work.entry, &thread->todo); + } else { + list_add_tail(&death->work.entry, &proc->todo); + wake_up_interruptible(&proc->wait); } } else { BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; } - binder_inner_proc_unlock(proc); } - binder_node_unlock(ref->node); - binder_proc_unlock(proc); } break; case BC_DEAD_BINDER_DONE: { struct binder_work *w; binder_uintptr_t cookie; struct binder_ref_death *death = NULL; - - if (get_user(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(cookie); - binder_inner_proc_lock(proc); - list_for_each_entry(w, &proc->delivered_death, - entry) { - struct binder_ref_death *tmp_death = - container_of(w, - struct binder_ref_death, - work); + list_for_each_entry(w, &proc->delivered_death, entry) { + struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); if (tmp_death->cookie == cookie) { death = tmp_death; @@ -3760,26 +2703,21 @@ static int binder_thread_write(struct binder_proc *proc, if (death == NULL) { binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", proc->pid, thread->pid, (u64)cookie); - binder_inner_proc_unlock(proc); break; } - binder_dequeue_work_ilocked(&death->work); + + list_del_init(&death->work.entry); if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & - (BINDER_LOOPER_STATE_REGISTERED | - BINDER_LOOPER_STATE_ENTERED)) - binder_enqueue_work_ilocked( - &death->work, &thread->todo); - else { - binder_enqueue_work_ilocked( - &death->work, - &proc->todo); - binder_wakeup_proc_ilocked(proc); + if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { + list_add_tail(&death->work.entry, &thread->todo); + } else { + list_add_tail(&death->work.entry, &proc->todo); + wake_up_interruptible(&proc->wait); } } - binder_inner_proc_unlock(proc); - } break; + } + break; default: pr_err("%d:%d unknown command %d\n", @@ -3795,80 +2733,24 @@ static void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, uint32_t cmd) { trace_binder_return(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { - atomic_inc(&binder_stats.br[_IOC_NR(cmd)]); - atomic_inc(&proc->stats.br[_IOC_NR(cmd)]); - atomic_inc(&thread->stats.br[_IOC_NR(cmd)]); + if (_IOC_NR(cmd) < ARRAY_SIZE(proc->stats.br)) { + proc->context->binder_stats.br[_IOC_NR(cmd)]++; + proc->stats.br[_IOC_NR(cmd)]++; + thread->stats.br[_IOC_NR(cmd)]++; } } -static int binder_has_thread_work(struct binder_thread *thread) -{ - return !binder_worklist_empty(thread->proc, &thread->todo) || - thread->looper_need_return; -} - -static int binder_put_node_cmd(struct binder_proc *proc, - struct binder_thread *thread, - void __user **ptrp, - binder_uintptr_t node_ptr, - binder_uintptr_t node_cookie, - int node_debug_id, - uint32_t cmd, const char *cmd_name) +static int binder_has_proc_work(struct binder_proc *proc, + struct binder_thread *thread) { - void __user *ptr = *ptrp; - - if (put_user(cmd, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - - if (put_user(node_ptr, (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - - if (put_user(node_cookie, (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - - binder_stat_br(proc, thread, cmd); - binder_debug(BINDER_DEBUG_USER_REFS, "%d:%d %s %d u%016llx c%016llx\n", - proc->pid, thread->pid, cmd_name, node_debug_id, - (u64)node_ptr, (u64)node_cookie); - - *ptrp = ptr; - return 0; + return !list_empty(&proc->todo) || + (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); } -static int binder_wait_for_work(struct binder_thread *thread, - bool do_proc_work) +static int binder_has_thread_work(struct binder_thread *thread) { - DEFINE_WAIT(wait); - struct binder_proc *proc = thread->proc; - int ret = 0; - - freezer_do_not_count(); - binder_inner_proc_lock(proc); - for (;;) { - prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE); - if (binder_has_work_ilocked(thread, do_proc_work)) - break; - if (do_proc_work) - list_add(&thread->waiting_thread_node, - &proc->waiting_threads); - binder_inner_proc_unlock(proc); - schedule(); - binder_inner_proc_lock(proc); - list_del_init(&thread->waiting_thread_node); - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - } - finish_wait(&thread->wait, &wait); - binder_inner_proc_unlock(proc); - freezer_count(); - - return ret; + return !list_empty(&thread->todo) || thread->return_error != BR_OK || + (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); } static int binder_thread_read(struct binder_proc *proc, @@ -3884,21 +2766,43 @@ static int binder_thread_read(struct binder_proc *proc, int wait_for_proc_work; if (*consumed == 0) { - if (put_user(BR_NOOP, (uint32_t __user *)ptr)) + if (put_user_preempt_disabled(BR_NOOP, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); } retry: - binder_inner_proc_lock(proc); - wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); - binder_inner_proc_unlock(proc); + wait_for_proc_work = thread->transaction_stack == NULL && + list_empty(&thread->todo); + + if (thread->return_error != BR_OK && ptr < end) { + if (thread->return_error2 != BR_OK) { + if (put_user_preempt_disabled(thread->return_error2, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + binder_stat_br(proc, thread, thread->return_error2); + if (ptr == end) + goto done; + thread->return_error2 = BR_OK; + } + if (put_user_preempt_disabled(thread->return_error, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + binder_stat_br(proc, thread, thread->return_error); + thread->return_error = BR_OK; + goto done; + } + thread->looper |= BINDER_LOOPER_STATE_WAITING; + if (wait_for_proc_work) + proc->ready_threads++; + + binder_unlock(proc->context, __func__); trace_binder_wait_for_work(wait_for_proc_work, !!thread->transaction_stack, - !binder_worklist_empty(proc, &thread->todo)); + !list_empty(&thread->todo)); if (wait_for_proc_work) { if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) { @@ -3907,16 +2811,25 @@ retry: wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); } - binder_restore_priority(current, proc->default_priority); - } - - if (non_block) { - if (!binder_has_work(thread, wait_for_proc_work)) - ret = -EAGAIN; + binder_set_nice(proc->default_priority); + if (non_block) { + if (!binder_has_proc_work(proc, thread)) + ret = -EAGAIN; + } else + ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread)); } else { - ret = binder_wait_for_work(thread, wait_for_proc_work); + if (non_block) { + if (!binder_has_thread_work(thread)) + ret = -EAGAIN; + } else + ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); } + if (binder_lock(proc->context, __func__)) + return -EINTR; + + if (wait_for_proc_work) + proc->ready_threads--; thread->looper &= ~BINDER_LOOPER_STATE_WAITING; if (ret) @@ -3925,54 +2838,33 @@ retry: while (1) { uint32_t cmd; struct binder_transaction_data tr; - struct binder_work *w = NULL; - struct list_head *list = NULL; + struct binder_work *w; struct binder_transaction *t = NULL; - struct binder_thread *t_from; - - binder_inner_proc_lock(proc); - if (!binder_worklist_empty_ilocked(&thread->todo)) - list = &thread->todo; - else if (!binder_worklist_empty_ilocked(&proc->todo) && - wait_for_proc_work) - list = &proc->todo; - else { - binder_inner_proc_unlock(proc); + if (!list_empty(&thread->todo)) { + w = list_first_entry(&thread->todo, struct binder_work, + entry); + } else if (!list_empty(&proc->todo) && wait_for_proc_work) { + w = list_first_entry(&proc->todo, struct binder_work, + entry); + } else { /* no data added */ - if (ptr - buffer == 4 && !thread->looper_need_return) + if (ptr - buffer == 4 && + !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) goto retry; break; } - if (end - ptr < sizeof(tr) + 4) { - binder_inner_proc_unlock(proc); + if (end - ptr < sizeof(tr) + 4) break; - } - w = binder_dequeue_work_head_ilocked(list); switch (w->type) { case BINDER_WORK_TRANSACTION: { - binder_inner_proc_unlock(proc); t = container_of(w, struct binder_transaction, work); } break; - case BINDER_WORK_RETURN_ERROR: { - struct binder_error *e = container_of( - w, struct binder_error, work); - - WARN_ON(e->cmd == BR_OK); - binder_inner_proc_unlock(proc); - if (put_user(e->cmd, (uint32_t __user *)ptr)) - return -EFAULT; - e->cmd = BR_OK; - ptr += sizeof(uint32_t); - - binder_stat_br(proc, thread, cmd); - } break; case BINDER_WORK_TRANSACTION_COMPLETE: { - binder_inner_proc_unlock(proc); cmd = BR_TRANSACTION_COMPLETE; - if (put_user(cmd, (uint32_t __user *)ptr)) + if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr)) return -EFAULT; ptr += sizeof(uint32_t); @@ -3980,134 +2872,112 @@ retry: binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, "%d:%d BR_TRANSACTION_COMPLETE\n", proc->pid, thread->pid); + + list_del(&w->entry); kfree(w); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); } break; case BINDER_WORK_NODE: { struct binder_node *node = container_of(w, struct binder_node, work); - int strong, weak; - binder_uintptr_t node_ptr = node->ptr; - binder_uintptr_t node_cookie = node->cookie; - int node_debug_id = node->debug_id; - int has_weak_ref; - int has_strong_ref; - void __user *orig_ptr = ptr; - - BUG_ON(proc != node->proc); - strong = node->internal_strong_refs || - node->local_strong_refs; - weak = !hlist_empty(&node->refs) || - node->local_weak_refs || - node->tmp_refs || strong; - has_strong_ref = node->has_strong_ref; - has_weak_ref = node->has_weak_ref; - - if (weak && !has_weak_ref) { + uint32_t cmd = BR_NOOP; + const char *cmd_name; + int strong = node->internal_strong_refs || node->local_strong_refs; + int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; + + if (weak && !node->has_weak_ref) { + cmd = BR_INCREFS; + cmd_name = "BR_INCREFS"; node->has_weak_ref = 1; node->pending_weak_ref = 1; node->local_weak_refs++; - } - if (strong && !has_strong_ref) { + } else if (strong && !node->has_strong_ref) { + cmd = BR_ACQUIRE; + cmd_name = "BR_ACQUIRE"; node->has_strong_ref = 1; node->pending_strong_ref = 1; node->local_strong_refs++; - } - if (!strong && has_strong_ref) + } else if (!strong && node->has_strong_ref) { + cmd = BR_RELEASE; + cmd_name = "BR_RELEASE"; node->has_strong_ref = 0; - if (!weak && has_weak_ref) + } else if (!weak && node->has_weak_ref) { + cmd = BR_DECREFS; + cmd_name = "BR_DECREFS"; node->has_weak_ref = 0; - if (!weak && !strong) { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%016llx c%016llx deleted\n", - proc->pid, thread->pid, - node_debug_id, - (u64)node_ptr, - (u64)node_cookie); - rb_erase(&node->rb_node, &proc->nodes); - binder_inner_proc_unlock(proc); - binder_node_lock(node); - /* - * Acquire the node lock before freeing the - * node to serialize with other threads that - * may have been holding the node lock while - * decrementing this node (avoids race where - * this thread frees while the other thread - * is unlocking the node after the final - * decrement) - */ - binder_node_unlock(node); - binder_free_node(node); - } else - binder_inner_proc_unlock(proc); - - if (weak && !has_weak_ref) - ret = binder_put_node_cmd( - proc, thread, &ptr, node_ptr, - node_cookie, node_debug_id, - BR_INCREFS, "BR_INCREFS"); - if (!ret && strong && !has_strong_ref) - ret = binder_put_node_cmd( - proc, thread, &ptr, node_ptr, - node_cookie, node_debug_id, - BR_ACQUIRE, "BR_ACQUIRE"); - if (!ret && !strong && has_strong_ref) - ret = binder_put_node_cmd( - proc, thread, &ptr, node_ptr, - node_cookie, node_debug_id, - BR_RELEASE, "BR_RELEASE"); - if (!ret && !weak && has_weak_ref) - ret = binder_put_node_cmd( - proc, thread, &ptr, node_ptr, - node_cookie, node_debug_id, - BR_DECREFS, "BR_DECREFS"); - if (orig_ptr == ptr) - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%016llx c%016llx state unchanged\n", - proc->pid, thread->pid, - node_debug_id, - (u64)node_ptr, - (u64)node_cookie); - if (ret) - return ret; + } + if (cmd != BR_NOOP) { + if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (put_user_preempt_disabled(node->ptr, (binder_uintptr_t __user *) + (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + if (put_user_preempt_disabled(node->cookie, (binder_uintptr_t __user *) + (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + + binder_stat_br(proc, thread, cmd); + binder_debug(BINDER_DEBUG_USER_REFS, + "%d:%d %s %d u%016llx c%016llx\n", + proc->pid, thread->pid, cmd_name, + node->debug_id, + (u64)node->ptr, (u64)node->cookie); + } else { + list_del_init(&w->entry); + if (!weak && !strong) { + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx deleted\n", + proc->pid, thread->pid, + node->debug_id, + (u64)node->ptr, + (u64)node->cookie); + rb_erase(&node->rb_node, &proc->nodes); + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); + } else { + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx state unchanged\n", + proc->pid, thread->pid, + node->debug_id, + (u64)node->ptr, + (u64)node->cookie); + } + } } break; case BINDER_WORK_DEAD_BINDER: case BINDER_WORK_DEAD_BINDER_AND_CLEAR: case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { struct binder_ref_death *death; uint32_t cmd; - binder_uintptr_t cookie; death = container_of(w, struct binder_ref_death, work); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; else cmd = BR_DEAD_BINDER; - cookie = death->cookie; - + if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (put_user_preempt_disabled(death->cookie, (binder_uintptr_t __user *) ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, "%d:%d %s %016llx\n", proc->pid, thread->pid, cmd == BR_DEAD_BINDER ? "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE", - (u64)cookie); + (u64)death->cookie); + if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { - binder_inner_proc_unlock(proc); + list_del(&w->entry); kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); - } else { - binder_enqueue_work_ilocked( - w, &proc->delivered_death); - binder_inner_proc_unlock(proc); - } - if (put_user(cmd, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - if (put_user(cookie, - (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - binder_stat_br(proc, thread, cmd); + } else + list_move(&w->entry, &proc->delivered_death); if (cmd == BR_DEAD_BINDER) goto done; /* DEAD_BINDER notifications can cause transactions */ } break; @@ -4119,14 +2989,16 @@ retry: BUG_ON(t->buffer == NULL); if (t->buffer->target_node) { struct binder_node *target_node = t->buffer->target_node; - struct binder_priority node_prio; tr.target.ptr = target_node->ptr; tr.cookie = target_node->cookie; - node_prio.sched_policy = target_node->sched_policy; - node_prio.prio = target_node->min_priority; - binder_transaction_priority(current, t, node_prio, - target_node->inherit_rt); + t->saved_priority = task_nice(current); + if (t->priority < target_node->min_priority && + !(t->flags & TF_ONE_WAY)) + binder_set_nice(t->priority); + else if (!(t->flags & TF_ONE_WAY) || + t->saved_priority > target_node->min_priority) + binder_set_nice(target_node->min_priority); cmd = BR_TRANSACTION; } else { tr.target.ptr = 0; @@ -4137,9 +3009,8 @@ retry: tr.flags = t->flags; tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); - t_from = binder_get_txn_from(t); - if (t_from) { - struct task_struct *sender = t_from->proc->tsk; + if (t->from) { + struct task_struct *sender = t->from->proc->tsk; tr.sender_pid = task_tgid_nr_ns(sender, task_active_pid_ns(current)); @@ -4149,24 +3020,18 @@ retry: tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (binder_uintptr_t) - ((uintptr_t)t->buffer->data + - binder_alloc_get_user_buffer_offset(&proc->alloc)); + tr.data.ptr.buffer = (binder_uintptr_t)( + (uintptr_t)t->buffer->data + + proc->user_buffer_offset); tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); - if (put_user(cmd, (uint32_t __user *)ptr)) { - if (t_from) - binder_thread_dec_tmpref(t_from); + if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr)) return -EFAULT; - } ptr += sizeof(uint32_t); - if (copy_to_user(ptr, &tr, sizeof(tr))) { - if (t_from) - binder_thread_dec_tmpref(t_from); + if (copy_to_user_preempt_disabled(ptr, &tr, sizeof(tr))) return -EFAULT; - } ptr += sizeof(tr); trace_binder_transaction_received(t); @@ -4176,22 +3041,21 @@ retry: proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : "BR_REPLY", - t->debug_id, t_from ? t_from->proc->pid : 0, - t_from ? t_from->pid : 0, cmd, + t->debug_id, t->from ? t->from->proc->pid : 0, + t->from ? t->from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); - if (t_from) - binder_thread_dec_tmpref(t_from); + list_del(&t->work.entry); t->buffer->allow_user_free = 1; if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { - binder_inner_proc_lock(thread->proc); t->to_parent = thread->transaction_stack; t->to_thread = thread; thread->transaction_stack = t; - binder_inner_proc_unlock(thread->proc); } else { - binder_free_transaction(t); + t->buffer->transaction = NULL; + kfree(t); + binder_stats_deleted(BINDER_STAT_TRANSACTION); } break; } @@ -4199,36 +3063,29 @@ retry: done: *consumed = ptr - buffer; - binder_inner_proc_lock(proc); - if (proc->requested_threads == 0 && - list_empty(&thread->proc->waiting_threads) && + if (proc->requested_threads + proc->ready_threads == 0 && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) { proc->requested_threads++; - binder_inner_proc_unlock(proc); binder_debug(BINDER_DEBUG_THREADS, "%d:%d BR_SPAWN_LOOPER\n", proc->pid, thread->pid); - if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) + if (put_user_preempt_disabled(BR_SPAWN_LOOPER, (uint32_t __user *) buffer)) return -EFAULT; binder_stat_br(proc, thread, BR_SPAWN_LOOPER); - } else - binder_inner_proc_unlock(proc); + } return 0; } -static void binder_release_work(struct binder_proc *proc, - struct list_head *list) +static void binder_release_work(struct list_head *list) { struct binder_work *w; - while (1) { - w = binder_dequeue_work_head(proc, list); - if (!w) - return; - + while (!list_empty(list)) { + w = list_first_entry(list, struct binder_work, entry); + list_del_init(&w->entry); switch (w->type) { case BINDER_WORK_TRANSACTION: { struct binder_transaction *t; @@ -4241,17 +3098,11 @@ static void binder_release_work(struct binder_proc *proc, binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, "undelivered transaction %d\n", t->debug_id); - binder_free_transaction(t); + t->buffer->transaction = NULL; + kfree(t); + binder_stats_deleted(BINDER_STAT_TRANSACTION); } } break; - case BINDER_WORK_RETURN_ERROR: { - struct binder_error *e = container_of( - w, struct binder_error, work); - - binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered TRANSACTION_ERROR: %u\n", - e->cmd); - } break; case BINDER_WORK_TRANSACTION_COMPLETE: { binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, "undelivered TRANSACTION_COMPLETE\n"); @@ -4278,8 +3129,7 @@ static void binder_release_work(struct binder_proc *proc, } -static struct binder_thread *binder_get_thread_ilocked( - struct binder_proc *proc, struct binder_thread *new_thread) +static struct binder_thread *binder_get_thread(struct binder_proc *proc) { struct binder_thread *thread = NULL; struct rb_node *parent = NULL; @@ -4290,106 +3140,42 @@ static struct binder_thread *binder_get_thread_ilocked( thread = rb_entry(parent, struct binder_thread, rb_node); if (current->pid < thread->pid) - p = &(*p)->rb_left; - else if (current->pid > thread->pid) - p = &(*p)->rb_right; - else - return thread; - } - if (!new_thread) - return NULL; - thread = new_thread; - binder_stats_created(BINDER_STAT_THREAD); - thread->proc = proc; - thread->pid = current->pid; - get_task_struct(current); - thread->task = current; - atomic_set(&thread->tmp_ref, 0); - init_waitqueue_head(&thread->wait); - INIT_LIST_HEAD(&thread->todo); - rb_link_node(&thread->rb_node, parent, p); - rb_insert_color(&thread->rb_node, &proc->threads); - thread->looper_need_return = true; - thread->return_error.work.type = BINDER_WORK_RETURN_ERROR; - thread->return_error.cmd = BR_OK; - thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR; - thread->reply_error.cmd = BR_OK; - INIT_LIST_HEAD(&new_thread->waiting_thread_node); - return thread; -} - -static struct binder_thread *binder_get_thread(struct binder_proc *proc) -{ - struct binder_thread *thread; - struct binder_thread *new_thread; - - binder_inner_proc_lock(proc); - thread = binder_get_thread_ilocked(proc, NULL); - binder_inner_proc_unlock(proc); - if (!thread) { - new_thread = kzalloc(sizeof(*thread), GFP_KERNEL); - if (new_thread == NULL) + p = &(*p)->rb_left; + else if (current->pid > thread->pid) + p = &(*p)->rb_right; + else + break; + } + if (*p == NULL) { + thread = kzalloc_preempt_disabled(sizeof(*thread)); + if (thread == NULL) return NULL; - binder_inner_proc_lock(proc); - thread = binder_get_thread_ilocked(proc, new_thread); - binder_inner_proc_unlock(proc); - if (thread != new_thread) - kfree(new_thread); + binder_stats_created(BINDER_STAT_THREAD); + thread->proc = proc; + thread->pid = current->pid; + init_waitqueue_head(&thread->wait); + INIT_LIST_HEAD(&thread->todo); + rb_link_node(&thread->rb_node, parent, p); + rb_insert_color(&thread->rb_node, &proc->threads); + thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; + thread->return_error = BR_OK; + thread->return_error2 = BR_OK; } return thread; } -static void binder_free_proc(struct binder_proc *proc) -{ - BUG_ON(!list_empty(&proc->todo)); - BUG_ON(!list_empty(&proc->delivered_death)); - binder_alloc_deferred_release(&proc->alloc); - put_task_struct(proc->tsk); - binder_stats_deleted(BINDER_STAT_PROC); - kfree(proc); -} - -static void binder_free_thread(struct binder_thread *thread) -{ - BUG_ON(!list_empty(&thread->todo)); - binder_stats_deleted(BINDER_STAT_THREAD); - binder_proc_dec_tmpref(thread->proc); - put_task_struct(thread->task); - kfree(thread); -} - -static int binder_thread_release(struct binder_proc *proc, - struct binder_thread *thread) +static int binder_free_thread(struct binder_proc *proc, + struct binder_thread *thread) { struct binder_transaction *t; struct binder_transaction *send_reply = NULL; int active_transactions = 0; - struct binder_transaction *last_t = NULL; - binder_inner_proc_lock(thread->proc); - /* - * take a ref on the proc so it survives - * after we remove this thread from proc->threads. - * The corresponding dec is when we actually - * free the thread in binder_free_thread() - */ - proc->tmp_ref++; - /* - * take a ref on this thread to ensure it - * survives while we are releasing it - */ - atomic_inc(&thread->tmp_ref); rb_erase(&thread->rb_node, &proc->threads); t = thread->transaction_stack; - if (t) { - spin_lock(&t->lock); - if (t->to_thread == thread) - send_reply = t; - } - thread->is_dead = true; - + if (t && t->to_thread == thread) + send_reply = t; while (t) { - last_t = t; active_transactions++; binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, "release %d:%d transaction %d %s, still active\n", @@ -4410,16 +3196,12 @@ static int binder_thread_release(struct binder_proc *proc, t = t->from_parent; } else BUG(); - spin_unlock(&last_t->lock); - if (t) - spin_lock(&t->lock); } - binder_inner_proc_unlock(thread->proc); - if (send_reply) binder_send_failed_reply(send_reply, BR_DEAD_REPLY); - binder_release_work(proc, &thread->todo); - binder_thread_dec_tmpref(thread); + binder_release_work(&thread->todo); + kfree(thread); + binder_stats_deleted(BINDER_STAT_THREAD); return active_transactions; } @@ -4428,24 +3210,31 @@ static unsigned int binder_poll(struct file *filp, { struct binder_proc *proc = filp->private_data; struct binder_thread *thread = NULL; - bool wait_for_proc_work; - - thread = binder_get_thread(proc); - - binder_inner_proc_lock(thread->proc); - thread->looper |= BINDER_LOOPER_STATE_POLL; - wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); + int wait_for_proc_work; - binder_inner_proc_unlock(thread->proc); + if (binder_lock(proc->context, __func__)) + return 0; - if (binder_has_work(thread, wait_for_proc_work)) - return POLLIN; + thread = binder_get_thread(proc); - poll_wait(filp, &thread->wait, wait); + wait_for_proc_work = thread->transaction_stack == NULL && + list_empty(&thread->todo) && thread->return_error == BR_OK; - if (binder_has_thread_work(thread)) - return POLLIN; + binder_unlock(proc->context, __func__); + if (wait_for_proc_work) { + if (binder_has_proc_work(proc, thread)) + return POLLIN; + poll_wait(filp, &proc->wait, wait); + if (binder_has_proc_work(proc, thread)) + return POLLIN; + } else { + if (binder_has_thread_work(thread)) + return POLLIN; + poll_wait(filp, &thread->wait, wait); + if (binder_has_thread_work(thread)) + return POLLIN; + } return 0; } @@ -4463,7 +3252,7 @@ static int binder_ioctl_write_read(struct file *filp, ret = -EINVAL; goto out; } - if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { + if (copy_from_user_preempt_disabled(&bwr, ubuf, sizeof(bwr))) { ret = -EFAULT; goto out; } @@ -4481,7 +3270,7 @@ static int binder_ioctl_write_read(struct file *filp, trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; - if (copy_to_user(ubuf, &bwr, sizeof(bwr))) + if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto out; } @@ -4492,12 +3281,12 @@ static int binder_ioctl_write_read(struct file *filp, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); trace_binder_read_done(ret); - binder_inner_proc_lock(proc); - if (!binder_worklist_empty_ilocked(&proc->todo)) - binder_wakeup_proc_ilocked(proc); - binder_inner_proc_unlock(proc); + if (!list_empty(&proc->todo)) + wake_up_interruptible(&proc->wait); if (ret < 0) { - if (copy_to_user(ubuf, &bwr, sizeof(bwr))) + if (ret == -EINTR) + goto out; + if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto out; } @@ -4507,7 +3296,7 @@ static int binder_ioctl_write_read(struct file *filp, proc->pid, thread->pid, (u64)bwr.write_consumed, (u64)bwr.write_size, (u64)bwr.read_consumed, (u64)bwr.read_size); - if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { + if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto out; } @@ -4520,10 +3309,9 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) int ret = 0; struct binder_proc *proc = filp->private_data; struct binder_context *context = proc->context; - struct binder_node *new_node; + kuid_t curr_euid = current_euid(); - mutex_lock(&context->context_mgr_node_lock); if (context->binder_context_mgr_node) { pr_err("BINDER_SET_CONTEXT_MGR already set\n"); ret = -EBUSY; @@ -4544,52 +3332,24 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) } else { context->binder_context_mgr_uid = curr_euid; } - new_node = binder_new_node(proc, NULL); - if (!new_node) { + context->binder_context_mgr_node = binder_new_node(proc, 0, 0); + if (!context->binder_context_mgr_node) { ret = -ENOMEM; goto out; } - binder_node_lock(new_node); - new_node->local_weak_refs++; - new_node->local_strong_refs++; - new_node->has_strong_ref = 1; - new_node->has_weak_ref = 1; - context->binder_context_mgr_node = new_node; - binder_node_unlock(new_node); - binder_put_node(new_node); + context->binder_context_mgr_node->local_weak_refs++; + context->binder_context_mgr_node->local_strong_refs++; + context->binder_context_mgr_node->has_strong_ref = 1; + context->binder_context_mgr_node->has_weak_ref = 1; out: - mutex_unlock(&context->context_mgr_node_lock); return ret; } -static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, - struct binder_node_debug_info *info) { - struct rb_node *n; - binder_uintptr_t ptr = info->ptr; - - memset(info, 0, sizeof(*info)); - - binder_inner_proc_lock(proc); - for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { - struct binder_node *node = rb_entry(n, struct binder_node, - rb_node); - if (node->ptr > ptr) { - info->ptr = node->ptr; - info->cookie = node->cookie; - info->has_strong_ref = node->has_strong_ref; - info->has_weak_ref = node->has_weak_ref; - break; - } - } - binder_inner_proc_unlock(proc); - - return 0; -} - static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; struct binder_proc *proc = filp->private_data; + struct binder_context *context = proc->context; struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg; @@ -4603,6 +3363,10 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (ret) goto err_unlocked; + if (binder_lock(context, __func__)) { + ret = -EINTR; + goto err_unlocked; + } thread = binder_get_thread(proc); if (thread == NULL) { ret = -ENOMEM; @@ -4612,22 +3376,18 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case BINDER_WRITE_READ: ret = binder_ioctl_write_read(filp, cmd, arg, thread); - if (ret) + if (ret) { + if (ret == -EINTR) + goto err_unlocked; goto err; + } break; - case BINDER_SET_MAX_THREADS: { - int max_threads; - - if (copy_from_user(&max_threads, ubuf, - sizeof(max_threads))) { + case BINDER_SET_MAX_THREADS: + if (copy_from_user_preempt_disabled(&proc->max_threads, ubuf, sizeof(proc->max_threads))) { ret = -EINVAL; goto err; } - binder_inner_proc_lock(proc); - proc->max_threads = max_threads; - binder_inner_proc_unlock(proc); break; - } case BINDER_SET_CONTEXT_MGR: ret = binder_ioctl_set_ctx_mgr(filp); if (ret) @@ -4636,7 +3396,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case BINDER_THREAD_EXIT: binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n", proc->pid, thread->pid); - binder_thread_release(proc, thread); + binder_free_thread(proc, thread); thread = NULL; break; case BINDER_VERSION: { @@ -4646,27 +3406,8 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = -EINVAL; goto err; } - if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, - &ver->protocol_version)) { - ret = -EINVAL; - goto err; - } - break; - } - case BINDER_GET_NODE_DEBUG_INFO: { - struct binder_node_debug_info info; - - if (copy_from_user(&info, ubuf, sizeof(info))) { - ret = -EFAULT; - goto err; - } - - ret = binder_ioctl_get_node_debug_info(proc, &info); - if (ret < 0) - goto err; - - if (copy_to_user(ubuf, &info, sizeof(info))) { - ret = -EFAULT; + if (put_user_preempt_disabled(BINDER_CURRENT_PROTOCOL_VERSION, &ver->protocol_version)) { + ret = -EINVAL; goto err; } break; @@ -4678,7 +3419,8 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = 0; err: if (thread) - thread->looper_need_return = false; + thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; + binder_unlock(context, __func__); wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret && ret != -ERESTARTSYS) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); @@ -4707,7 +3449,8 @@ static void binder_vma_close(struct vm_area_struct *vma) proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); - binder_alloc_vma_close(&proc->alloc); + proc->vma = NULL; + proc->vma_vm_mm = NULL; binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); } @@ -4725,8 +3468,11 @@ static const struct vm_operations_struct binder_vm_ops = { static int binder_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; + + struct vm_struct *area; struct binder_proc *proc = filp->private_data; const char *failure_string; + struct binder_buffer *buffer; if (proc->tsk != current->group_leader) return -EINVAL; @@ -4735,8 +3481,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_end = vma->vm_start + SZ_4M; binder_debug(BINDER_DEBUG_OPEN_CLOSE, - "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", - __func__, proc->pid, vma->vm_start, vma->vm_end, + "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", + proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); @@ -4746,15 +3492,77 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) goto err_bad_arg; } vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; + + mutex_lock(&proc->context->binder_mmap_lock); + if (proc->buffer) { + ret = -EBUSY; + failure_string = "already mapped"; + goto err_already_mapped; + } + + area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); + if (area == NULL) { + ret = -ENOMEM; + failure_string = "get_vm_area"; + goto err_get_vm_area_failed; + } + proc->buffer = area->addr; + proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; + mutex_unlock(&proc->context->binder_mmap_lock); + +#ifdef CONFIG_CPU_CACHE_VIPT + if (cache_is_vipt_aliasing()) { + while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { + pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); + vma->vm_start += PAGE_SIZE; + } + } +#endif + proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL); + if (proc->pages == NULL) { + ret = -ENOMEM; + failure_string = "alloc page array"; + goto err_alloc_pages_failed; + } + proc->buffer_size = vma->vm_end - vma->vm_start; + vma->vm_ops = &binder_vm_ops; vma->vm_private_data = proc; - ret = binder_alloc_mmap_handler(&proc->alloc, vma); - if (ret) - return ret; + /* binder_update_page_range assumes preemption is disabled */ + preempt_disable(); + ret = binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma); + preempt_enable_no_resched(); + if (ret) { + ret = -ENOMEM; + failure_string = "alloc small buf"; + goto err_alloc_small_buf_failed; + } + buffer = proc->buffer; + INIT_LIST_HEAD(&proc->buffers); + list_add(&buffer->entry, &proc->buffers); + buffer->free = 1; + binder_insert_free_buffer(proc, buffer); + proc->free_async_space = proc->buffer_size / 2; + barrier(); proc->files = get_files_struct(current); + proc->vma = vma; + proc->vma_vm_mm = vma->vm_mm; + + /*pr_info("binder_mmap: %d %lx-%lx maps %p\n", + proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ return 0; +err_alloc_small_buf_failed: + kfree(proc->pages); + proc->pages = NULL; +err_alloc_pages_failed: + mutex_lock(&proc->context->binder_mmap_lock); + vfree(proc->buffer); + proc->buffer = NULL; +err_get_vm_area_failed: +err_already_mapped: + mutex_unlock(&proc->context->binder_mmap_lock); err_bad_arg: pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); @@ -4772,33 +3580,27 @@ static int binder_open(struct inode *nodp, struct file *filp) proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) return -ENOMEM; - spin_lock_init(&proc->inner_lock); - spin_lock_init(&proc->outer_lock); get_task_struct(current->group_leader); proc->tsk = current->group_leader; INIT_LIST_HEAD(&proc->todo); - if (binder_supported_policy(current->policy)) { - proc->default_priority.sched_policy = current->policy; - proc->default_priority.prio = current->normal_prio; - } else { - proc->default_priority.sched_policy = SCHED_NORMAL; - proc->default_priority.prio = NICE_TO_PRIO(0); - } - + init_waitqueue_head(&proc->wait); + proc->default_priority = task_nice(current); binder_dev = container_of(filp->private_data, struct binder_device, miscdev); proc->context = &binder_dev->context; - binder_alloc_init(&proc->alloc); + + if (binder_lock(proc->context, __func__)) { + kfree(proc); + return -EINTR; + } binder_stats_created(BINDER_STAT_PROC); + hlist_add_head(&proc->proc_node, &proc->context->binder_procs); proc->pid = current->group_leader->pid; INIT_LIST_HEAD(&proc->delivered_death); - INIT_LIST_HEAD(&proc->waiting_threads); filp->private_data = proc; - mutex_lock(&binder_procs_lock); - hlist_add_head(&proc->proc_node, &binder_procs); - mutex_unlock(&binder_procs_lock); + binder_unlock(proc->context, __func__); if (binder_debugfs_dir_entry_proc) { char strbuf[11]; @@ -4834,17 +3636,16 @@ static void binder_deferred_flush(struct binder_proc *proc) struct rb_node *n; int wake_count = 0; - binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); - thread->looper_need_return = true; + thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; if (thread->looper & BINDER_LOOPER_STATE_WAITING) { wake_up_interruptible(&thread->wait); wake_count++; } } - binder_inner_proc_unlock(proc); + wake_up_interruptible_all(&proc->wait); binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_flush: %d woke %d threads\n", proc->pid, @@ -4864,22 +3665,15 @@ static int binder_release(struct inode *nodp, struct file *filp) static int binder_node_release(struct binder_node *node, int refs) { struct binder_ref *ref; + struct binder_context *context = node->proc->context; int death = 0; - struct binder_proc *proc = node->proc; - binder_release_work(proc, &node->async_todo); + list_del_init(&node->work.entry); + binder_release_work(&node->async_todo); - binder_node_lock(node); - binder_inner_proc_lock(proc); - binder_dequeue_work_ilocked(&node->work); - /* - * The caller must have taken a temporary ref on the node, - */ - BUG_ON(!node->tmp_refs); - if (hlist_empty(&node->refs) && node->tmp_refs == 1) { - binder_inner_proc_unlock(proc); - binder_node_unlock(node); - binder_free_node(node); + if (hlist_empty(&node->refs)) { + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); return refs; } @@ -4887,58 +3681,45 @@ static int binder_node_release(struct binder_node *node, int refs) node->proc = NULL; node->local_strong_refs = 0; node->local_weak_refs = 0; - binder_inner_proc_unlock(proc); - - spin_lock(&binder_dead_nodes_lock); - hlist_add_head(&node->dead_node, &binder_dead_nodes); - spin_unlock(&binder_dead_nodes_lock); + hlist_add_head(&node->dead_node, &context->binder_dead_nodes); hlist_for_each_entry(ref, &node->refs, node_entry) { refs++; - /* - * Need the node lock to synchronize - * with new notification requests and the - * inner lock to synchronize with queued - * death notifications. - */ - binder_inner_proc_lock(ref->proc); - if (!ref->death) { - binder_inner_proc_unlock(ref->proc); + + if (!ref->death) continue; - } death++; - BUG_ON(!list_empty(&ref->death->work.entry)); - ref->death->work.type = BINDER_WORK_DEAD_BINDER; - binder_enqueue_work_ilocked(&ref->death->work, - &ref->proc->todo); - binder_wakeup_proc_ilocked(ref->proc); - binder_inner_proc_unlock(ref->proc); + if (list_empty(&ref->death->work.entry)) { + ref->death->work.type = BINDER_WORK_DEAD_BINDER; + list_add_tail(&ref->death->work.entry, + &ref->proc->todo); + wake_up_interruptible(&ref->proc->wait); + } else + BUG(); } binder_debug(BINDER_DEBUG_DEAD_BINDER, "node %d now dead, refs %d, death %d\n", node->debug_id, refs, death); - binder_node_unlock(node); - binder_put_node(node); return refs; } static void binder_deferred_release(struct binder_proc *proc) { + struct binder_transaction *t; struct binder_context *context = proc->context; struct rb_node *n; - int threads, nodes, incoming_refs, outgoing_refs, active_transactions; + int threads, nodes, incoming_refs, outgoing_refs, buffers, + active_transactions, page_count; + BUG_ON(proc->vma); BUG_ON(proc->files); - mutex_lock(&binder_procs_lock); hlist_del(&proc->proc_node); - mutex_unlock(&binder_procs_lock); - mutex_lock(&context->context_mgr_node_lock); if (context->binder_context_mgr_node && context->binder_context_mgr_node->proc == proc) { binder_debug(BINDER_DEBUG_DEAD_BINDER, @@ -4946,25 +3727,15 @@ static void binder_deferred_release(struct binder_proc *proc) __func__, proc->pid); context->binder_context_mgr_node = NULL; } - mutex_unlock(&context->context_mgr_node_lock); - binder_inner_proc_lock(proc); - /* - * Make sure proc stays alive after we - * remove all the threads - */ - proc->tmp_ref++; - proc->is_dead = true; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { struct binder_thread *thread; thread = rb_entry(n, struct binder_thread, rb_node); - binder_inner_proc_unlock(proc); threads++; - active_transactions += binder_thread_release(proc, thread); - binder_inner_proc_lock(proc); + active_transactions += binder_free_thread(proc, thread); } nodes = 0; @@ -4974,55 +3745,96 @@ static void binder_deferred_release(struct binder_proc *proc) node = rb_entry(n, struct binder_node, rb_node); nodes++; - /* - * take a temporary ref on the node before - * calling binder_node_release() which will either - * kfree() the node or call binder_put_node() - */ - binder_inc_node_tmpref_ilocked(node); rb_erase(&node->rb_node, &proc->nodes); - binder_inner_proc_unlock(proc); - incoming_refs = binder_node_release(node, incoming_refs); - binder_inner_proc_lock(proc); + incoming_refs = binder_node_release(node, + incoming_refs); } - binder_inner_proc_unlock(proc); outgoing_refs = 0; - binder_proc_lock(proc); while ((n = rb_first(&proc->refs_by_desc))) { struct binder_ref *ref; ref = rb_entry(n, struct binder_ref, rb_node_desc); outgoing_refs++; - binder_cleanup_ref_olocked(ref); - binder_proc_unlock(proc); - binder_free_ref(ref); - binder_proc_lock(proc); + binder_delete_ref(ref); + } + + binder_release_work(&proc->todo); + binder_release_work(&proc->delivered_death); + + buffers = 0; + while ((n = rb_first(&proc->allocated_buffers))) { + struct binder_buffer *buffer; + + buffer = rb_entry(n, struct binder_buffer, rb_node); + + t = buffer->transaction; + if (t) { + t->buffer = NULL; + buffer->transaction = NULL; + pr_err("release proc %d, transaction %d, not freed\n", + proc->pid, t->debug_id); + /*BUG();*/ + } + + binder_free_buf(proc, buffer); + buffers++; + } + + binder_stats_deleted(BINDER_STAT_PROC); + + page_count = 0; + if (proc->pages) { + int i; + + for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { + void *page_addr; + + if (!proc->pages[i]) + continue; + + page_addr = proc->buffer + i * PAGE_SIZE; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%s: %d: page %d at %p not freed\n", + __func__, proc->pid, i, page_addr); + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); + __free_page(proc->pages[i]); + page_count++; + } + kfree(proc->pages); + preempt_enable_no_resched(); + vfree(proc->buffer); + preempt_disable(); } - binder_proc_unlock(proc); - binder_release_work(proc, &proc->todo); - binder_release_work(proc, &proc->delivered_death); + put_task_struct(proc->tsk); binder_debug(BINDER_DEBUG_OPEN_CLOSE, - "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d\n", + "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n", __func__, proc->pid, threads, nodes, incoming_refs, - outgoing_refs, active_transactions); + outgoing_refs, active_transactions, buffers, page_count); - binder_proc_dec_tmpref(proc); + kfree(proc); } static void binder_deferred_func(struct work_struct *work) { struct binder_proc *proc; struct files_struct *files; + struct binder_context *context = + container_of(work, struct binder_context, deferred_work); int defer; do { - mutex_lock(&binder_deferred_lock); - if (!hlist_empty(&binder_deferred_list)) { - proc = hlist_entry(binder_deferred_list.first, + trace_binder_lock(__func__); + mutex_lock(&context->binder_main_lock); + trace_binder_locked(__func__); + + mutex_lock(&context->binder_deferred_lock); + preempt_disable(); + if (!hlist_empty(&context->binder_deferred_list)) { + proc = hlist_entry(context->binder_deferred_list.first, struct binder_proc, deferred_work_node); hlist_del_init(&proc->deferred_work_node); defer = proc->deferred_work; @@ -5031,7 +3843,7 @@ static void binder_deferred_func(struct work_struct *work) proc = NULL; defer = 0; } - mutex_unlock(&binder_deferred_lock); + mutex_unlock(&context->binder_deferred_lock); files = NULL; if (defer & BINDER_DEFERRED_PUT_FILES) { @@ -5046,72 +3858,63 @@ static void binder_deferred_func(struct work_struct *work) if (defer & BINDER_DEFERRED_RELEASE) binder_deferred_release(proc); /* frees proc */ + trace_binder_unlock(__func__); + mutex_unlock(&context->binder_main_lock); + preempt_enable_no_resched(); if (files) put_files_struct(files); } while (proc); } -static DECLARE_WORK(binder_deferred_work, binder_deferred_func); static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) { - mutex_lock(&binder_deferred_lock); + mutex_lock(&proc->context->binder_deferred_lock); proc->deferred_work |= defer; if (hlist_unhashed(&proc->deferred_work_node)) { hlist_add_head(&proc->deferred_work_node, - &binder_deferred_list); - queue_work(binder_deferred_workqueue, &binder_deferred_work); + &proc->context->binder_deferred_list); + queue_work(proc->context->binder_deferred_workqueue, + &proc->context->deferred_work); } - mutex_unlock(&binder_deferred_lock); + mutex_unlock(&proc->context->binder_deferred_lock); } -static void print_binder_transaction_ilocked(struct seq_file *m, - struct binder_proc *proc, - const char *prefix, - struct binder_transaction *t) +static void print_binder_transaction(struct seq_file *m, const char *prefix, + struct binder_transaction *t) { - struct binder_proc *to_proc; - struct binder_buffer *buffer = t->buffer; - - WARN_ON(!spin_is_locked(&proc->inner_lock)); - spin_lock(&t->lock); - to_proc = t->to_proc; seq_printf(m, - "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %d:%d r%d", + "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", prefix, t->debug_id, t, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, - to_proc ? to_proc->pid : 0, + t->to_proc ? t->to_proc->pid : 0, t->to_thread ? t->to_thread->pid : 0, - t->code, t->flags, t->priority.sched_policy, - t->priority.prio, t->need_reply); - spin_unlock(&t->lock); - - if (proc != to_proc) { - /* - * Can only safely deref buffer if we are holding the - * correct proc inner lock for this node - */ - seq_puts(m, "\n"); - return; - } - - if (buffer == NULL) { + t->code, t->flags, t->priority, t->need_reply); + if (t->buffer == NULL) { seq_puts(m, " buffer free\n"); return; } - if (buffer->target_node) - seq_printf(m, " node %d", buffer->target_node->debug_id); + if (t->buffer->target_node) + seq_printf(m, " node %d", + t->buffer->target_node->debug_id); seq_printf(m, " size %zd:%zd data %p\n", + t->buffer->data_size, t->buffer->offsets_size, + t->buffer->data); +} + +static void print_binder_buffer(struct seq_file *m, const char *prefix, + struct binder_buffer *buffer) +{ + seq_printf(m, "%s %d: %p size %zd:%zd %s\n", + prefix, buffer->debug_id, buffer->data, buffer->data_size, buffer->offsets_size, - buffer->data); + buffer->transaction ? "active" : "delivered"); } -static void print_binder_work_ilocked(struct seq_file *m, - struct binder_proc *proc, - const char *prefix, - const char *transaction_prefix, - struct binder_work *w) +static void print_binder_work(struct seq_file *m, const char *prefix, + const char *transaction_prefix, + struct binder_work *w) { struct binder_node *node; struct binder_transaction *t; @@ -5119,16 +3922,8 @@ static void print_binder_work_ilocked(struct seq_file *m, switch (w->type) { case BINDER_WORK_TRANSACTION: t = container_of(w, struct binder_transaction, work); - print_binder_transaction_ilocked( - m, proc, transaction_prefix, t); + print_binder_transaction(m, transaction_prefix, t); break; - case BINDER_WORK_RETURN_ERROR: { - struct binder_error *e = container_of( - w, struct binder_error, work); - - seq_printf(m, "%stransaction error: %u\n", - prefix, e->cmd); - } break; case BINDER_WORK_TRANSACTION_COMPLETE: seq_printf(m, "%stransaction complete\n", prefix); break; @@ -5153,90 +3948,70 @@ static void print_binder_work_ilocked(struct seq_file *m, } } -static void print_binder_thread_ilocked(struct seq_file *m, - struct binder_thread *thread, - int print_always) +static void print_binder_thread(struct seq_file *m, + struct binder_thread *thread, + int print_always) { struct binder_transaction *t; struct binder_work *w; size_t start_pos = m->count; size_t header_pos; - WARN_ON(!spin_is_locked(&thread->proc->inner_lock)); - seq_printf(m, " thread %d: l %02x need_return %d tr %d\n", - thread->pid, thread->looper, - thread->looper_need_return, - atomic_read(&thread->tmp_ref)); + seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper); header_pos = m->count; t = thread->transaction_stack; while (t) { if (t->from == thread) { - print_binder_transaction_ilocked(m, thread->proc, - " outgoing transaction", t); + print_binder_transaction(m, + " outgoing transaction", t); t = t->from_parent; } else if (t->to_thread == thread) { - print_binder_transaction_ilocked(m, thread->proc, + print_binder_transaction(m, " incoming transaction", t); t = t->to_parent; } else { - print_binder_transaction_ilocked(m, thread->proc, - " bad transaction", t); + print_binder_transaction(m, " bad transaction", t); t = NULL; } } list_for_each_entry(w, &thread->todo, entry) { - print_binder_work_ilocked(m, thread->proc, " ", - " pending transaction", w); + print_binder_work(m, " ", " pending transaction", w); } if (!print_always && m->count == header_pos) m->count = start_pos; } -static void print_binder_node_nilocked(struct seq_file *m, - struct binder_node *node) +static void print_binder_node(struct seq_file *m, struct binder_node *node) { struct binder_ref *ref; struct binder_work *w; int count; - WARN_ON(!spin_is_locked(&node->lock)); - if (node->proc) - WARN_ON(!spin_is_locked(&node->proc->inner_lock)); - count = 0; hlist_for_each_entry(ref, &node->refs, node_entry) count++; - seq_printf(m, " node %d: u%016llx c%016llx pri %d:%d hs %d hw %d ls %d lw %d is %d iw %d tr %d", + seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", node->debug_id, (u64)node->ptr, (u64)node->cookie, - node->sched_policy, node->min_priority, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, - node->internal_strong_refs, count, node->tmp_refs); + node->internal_strong_refs, count); if (count) { seq_puts(m, " proc"); hlist_for_each_entry(ref, &node->refs, node_entry) seq_printf(m, " %d", ref->proc->pid); } seq_puts(m, "\n"); - if (node->proc) { - list_for_each_entry(w, &node->async_todo, entry) - print_binder_work_ilocked(m, node->proc, " ", - " pending async transaction", w); - } + list_for_each_entry(w, &node->async_todo, entry) + print_binder_work(m, " ", + " pending async transaction", w); } -static void print_binder_ref_olocked(struct seq_file *m, - struct binder_ref *ref) +static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) { - WARN_ON(!spin_is_locked(&ref->proc->outer_lock)); - binder_node_lock(ref->node); seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %pK\n", - ref->data.debug_id, ref->data.desc, - ref->node->proc ? "" : "dead ", - ref->node->debug_id, ref->data.strong, - ref->data.weak, ref->death); - binder_node_unlock(ref->node); + ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", + ref->node->debug_id, ref->strong, ref->weak, ref->death); } static void print_binder_proc(struct seq_file *m, @@ -5246,60 +4021,36 @@ static void print_binder_proc(struct seq_file *m, struct rb_node *n; size_t start_pos = m->count; size_t header_pos; - struct binder_node *last_node = NULL; seq_printf(m, "proc %d\n", proc->pid); seq_printf(m, "context %s\n", proc->context->name); header_pos = m->count; - binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) - print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread, + print_binder_thread(m, rb_entry(n, struct binder_thread, rb_node), print_all); - for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { struct binder_node *node = rb_entry(n, struct binder_node, rb_node); - /* - * take a temporary reference on the node so it - * survives and isn't removed from the tree - * while we print it. - */ - binder_inc_node_tmpref_ilocked(node); - /* Need to drop inner lock to take node lock */ - binder_inner_proc_unlock(proc); - if (last_node) - binder_put_node(last_node); - binder_node_inner_lock(node); - print_binder_node_nilocked(m, node); - binder_node_inner_unlock(node); - last_node = node; - binder_inner_proc_lock(proc); - } - binder_inner_proc_unlock(proc); - if (last_node) - binder_put_node(last_node); - + if (print_all || node->has_async_transaction) + print_binder_node(m, node); + } if (print_all) { - binder_proc_lock(proc); for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) - print_binder_ref_olocked(m, rb_entry(n, - struct binder_ref, - rb_node_desc)); - binder_proc_unlock(proc); + print_binder_ref(m, rb_entry(n, struct binder_ref, + rb_node_desc)); } - binder_alloc_print_allocated(m, &proc->alloc); - binder_inner_proc_lock(proc); + for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) + print_binder_buffer(m, " buffer", + rb_entry(n, struct binder_buffer, rb_node)); list_for_each_entry(w, &proc->todo, entry) - print_binder_work_ilocked(m, proc, " ", - " pending transaction", w); + print_binder_work(m, " ", " pending transaction", w); list_for_each_entry(w, &proc->delivered_death, entry) { seq_puts(m, " has delivered dead binder\n"); break; } - binder_inner_proc_unlock(proc); if (!print_all && m->count == header_pos) m->count = start_pos; } @@ -5357,45 +4108,54 @@ static const char * const binder_objstat_strings[] = { "transaction_complete" }; +static void add_binder_stats(struct binder_stats *from, struct binder_stats *to) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(to->bc); i++) + to->bc[i] += from->bc[i]; + + for (i = 0; i < ARRAY_SIZE(to->br); i++) + to->br[i] += from->br[i]; +} + static void print_binder_stats(struct seq_file *m, const char *prefix, - struct binder_stats *stats) + struct binder_stats *stats, + struct binder_obj_stats *obj_stats) { int i; BUILD_BUG_ON(ARRAY_SIZE(stats->bc) != ARRAY_SIZE(binder_command_strings)); for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { - int temp = atomic_read(&stats->bc[i]); - - if (temp) + if (stats->bc[i]) seq_printf(m, "%s%s: %d\n", prefix, - binder_command_strings[i], temp); + binder_command_strings[i], stats->bc[i]); } BUILD_BUG_ON(ARRAY_SIZE(stats->br) != ARRAY_SIZE(binder_return_strings)); for (i = 0; i < ARRAY_SIZE(stats->br); i++) { - int temp = atomic_read(&stats->br[i]); - - if (temp) + if (stats->br[i]) seq_printf(m, "%s%s: %d\n", prefix, - binder_return_strings[i], temp); + binder_return_strings[i], stats->br[i]); } - BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != + if (!obj_stats) + return; + + BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) != ARRAY_SIZE(binder_objstat_strings)); - BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != - ARRAY_SIZE(stats->obj_deleted)); - for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { - int created = atomic_read(&stats->obj_created[i]); - int deleted = atomic_read(&stats->obj_deleted[i]); - - if (created || deleted) - seq_printf(m, "%s%s: active %d total %d\n", - prefix, - binder_objstat_strings[i], - created - deleted, - created); + BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) != + ARRAY_SIZE(obj_stats->obj_deleted)); + for (i = 0; i < ARRAY_SIZE(obj_stats->obj_created); i++) { + int obj_created = atomic_read(&obj_stats->obj_created[i]); + int obj_deleted = atomic_read(&obj_stats->obj_deleted[i]); + + if (obj_created || obj_deleted) + seq_printf(m, "%s%s: active %d total %d\n", prefix, + binder_objstat_strings[i], + obj_created - obj_deleted, obj_created); } } @@ -5403,193 +4163,232 @@ static void print_binder_proc_stats(struct seq_file *m, struct binder_proc *proc) { struct binder_work *w; - struct binder_thread *thread; struct rb_node *n; - int count, strong, weak, ready_threads; - size_t free_async_space = - binder_alloc_get_free_async_space(&proc->alloc); + int count, strong, weak; seq_printf(m, "proc %d\n", proc->pid); seq_printf(m, "context %s\n", proc->context->name); count = 0; - ready_threads = 0; - binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) count++; - - list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node) - ready_threads++; - seq_printf(m, " threads: %d\n", count); seq_printf(m, " requested threads: %d+%d/%d\n" " ready threads %d\n" " free async space %zd\n", proc->requested_threads, proc->requested_threads_started, proc->max_threads, - ready_threads, - free_async_space); + proc->ready_threads, proc->free_async_space); count = 0; for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) count++; - binder_inner_proc_unlock(proc); seq_printf(m, " nodes: %d\n", count); count = 0; strong = 0; weak = 0; - binder_proc_lock(proc); for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { struct binder_ref *ref = rb_entry(n, struct binder_ref, rb_node_desc); count++; - strong += ref->data.strong; - weak += ref->data.weak; + strong += ref->strong; + weak += ref->weak; } - binder_proc_unlock(proc); seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak); - count = binder_alloc_get_allocated_count(&proc->alloc); + count = 0; + for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) + count++; seq_printf(m, " buffers: %d\n", count); count = 0; - binder_inner_proc_lock(proc); list_for_each_entry(w, &proc->todo, entry) { - if (w->type == BINDER_WORK_TRANSACTION) + switch (w->type) { + case BINDER_WORK_TRANSACTION: count++; + break; + default: + break; + } } - binder_inner_proc_unlock(proc); seq_printf(m, " pending transactions: %d\n", count); - print_binder_stats(m, " ", &proc->stats); + print_binder_stats(m, " ", &proc->stats, NULL); } static int binder_state_show(struct seq_file *m, void *unused) { + struct binder_device *device; + struct binder_context *context; struct binder_proc *proc; struct binder_node *node; - struct binder_node *last_node = NULL; + int do_lock = !binder_debug_no_lock; + bool wrote_dead_nodes_header = false; seq_puts(m, "binder state:\n"); - spin_lock(&binder_dead_nodes_lock); - if (!hlist_empty(&binder_dead_nodes)) - seq_puts(m, "dead nodes:\n"); - hlist_for_each_entry(node, &binder_dead_nodes, dead_node) { - /* - * take a temporary reference on the node so it - * survives and isn't removed from the list - * while we print it. - */ - node->tmp_refs++; - spin_unlock(&binder_dead_nodes_lock); - if (last_node) - binder_put_node(last_node); - binder_node_lock(node); - print_binder_node_nilocked(m, node); - binder_node_unlock(node); - last_node = node; - spin_lock(&binder_dead_nodes_lock); - } - spin_unlock(&binder_dead_nodes_lock); - if (last_node) - binder_put_node(last_node); - - mutex_lock(&binder_procs_lock); - hlist_for_each_entry(proc, &binder_procs, proc_node) - print_binder_proc(m, proc, 1); - mutex_unlock(&binder_procs_lock); + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + if (binder_lock(context, __func__)) + return 0; + if (!wrote_dead_nodes_header && + !hlist_empty(&context->binder_dead_nodes)) { + seq_puts(m, "dead nodes:\n"); + wrote_dead_nodes_header = true; + } + hlist_for_each_entry(node, &context->binder_dead_nodes, + dead_node) + print_binder_node(m, node); + + if (do_lock) + binder_unlock(context, __func__); + } + + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + if (binder_lock(context, __func__)) + return 0; + hlist_for_each_entry(proc, &context->binder_procs, proc_node) + print_binder_proc(m, proc, 1); + if (do_lock) + binder_unlock(context, __func__); + } return 0; } static int binder_stats_show(struct seq_file *m, void *unused) { + struct binder_device *device; + struct binder_context *context; struct binder_proc *proc; + struct binder_stats total_binder_stats; + int do_lock = !binder_debug_no_lock; - seq_puts(m, "binder stats:\n"); + memset(&total_binder_stats, 0, sizeof(struct binder_stats)); - print_binder_stats(m, "", &binder_stats); + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + if (binder_lock(context, __func__)) + return 0; - mutex_lock(&binder_procs_lock); - hlist_for_each_entry(proc, &binder_procs, proc_node) - print_binder_proc_stats(m, proc); - mutex_unlock(&binder_procs_lock); + add_binder_stats(&context->binder_stats, &total_binder_stats); + if (do_lock) + binder_unlock(context, __func__); + } + + seq_puts(m, "binder stats:\n"); + print_binder_stats(m, "", &total_binder_stats, &binder_obj_stats); + + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + if (binder_lock(context, __func__)) + return 0; + + hlist_for_each_entry(proc, &context->binder_procs, proc_node) + print_binder_proc_stats(m, proc); + if (do_lock) + binder_unlock(context, __func__); + } return 0; } static int binder_transactions_show(struct seq_file *m, void *unused) { + struct binder_device *device; + struct binder_context *context; struct binder_proc *proc; + int do_lock = !binder_debug_no_lock; seq_puts(m, "binder transactions:\n"); - mutex_lock(&binder_procs_lock); - hlist_for_each_entry(proc, &binder_procs, proc_node) - print_binder_proc(m, proc, 0); - mutex_unlock(&binder_procs_lock); - + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + if (binder_lock(context, __func__)) + return 0; + + hlist_for_each_entry(proc, &context->binder_procs, proc_node) + print_binder_proc(m, proc, 0); + if (do_lock) + binder_unlock(context, __func__); + } return 0; } static int binder_proc_show(struct seq_file *m, void *unused) { + struct binder_device *device; + struct binder_context *context; struct binder_proc *itr; int pid = (unsigned long)m->private; - - mutex_lock(&binder_procs_lock); - hlist_for_each_entry(itr, &binder_procs, proc_node) { - if (itr->pid == pid) { - seq_puts(m, "binder proc state:\n"); - print_binder_proc(m, itr, 1); + int do_lock = !binder_debug_no_lock; + + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + if (binder_lock(context, __func__)) + return 0; + + hlist_for_each_entry(itr, &context->binder_procs, proc_node) { + if (itr->pid == pid) { + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, itr, 1); + } } + if (do_lock) + binder_unlock(context, __func__); } - mutex_unlock(&binder_procs_lock); - return 0; } static void print_binder_transaction_log_entry(struct seq_file *m, struct binder_transaction_log_entry *e) { - int debug_id = READ_ONCE(e->debug_id_done); - /* - * read barrier to guarantee debug_id_done read before - * we print the log values - */ - smp_rmb(); seq_printf(m, - "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d ret %d/%d l=%d", + "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d\n", e->debug_id, (e->call_type == 2) ? "reply" : ((e->call_type == 1) ? "async" : "call "), e->from_proc, e->from_thread, e->to_proc, e->to_thread, e->context_name, - e->to_node, e->target_handle, e->data_size, e->offsets_size, - e->return_error, e->return_error_param, - e->return_error_line); - /* - * read-barrier to guarantee read of debug_id_done after - * done printing the fields of the entry - */ - smp_rmb(); - seq_printf(m, debug_id && debug_id == READ_ONCE(e->debug_id_done) ? - "\n" : " (incomplete)\n"); + e->to_node, e->target_handle, e->data_size, e->offsets_size); } -static int binder_transaction_log_show(struct seq_file *m, void *unused) +static int print_binder_transaction_log(struct seq_file *m, + struct binder_transaction_log *log) { - struct binder_transaction_log *log = m->private; - unsigned int log_cur = atomic_read(&log->cur); - unsigned int count; - unsigned int cur; int i; + if (log->full) { + for (i = log->next; i < ARRAY_SIZE(log->entry); i++) + print_binder_transaction_log_entry(m, &log->entry[i]); + } + for (i = 0; i < log->next; i++) + print_binder_transaction_log_entry(m, &log->entry[i]); + return 0; +} + +static int binder_transaction_log_show(struct seq_file *m, void *unused) +{ + struct binder_device *device; + struct binder_context *context; + + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + print_binder_transaction_log(m, &context->transaction_log); + } + return 0; +} - count = log_cur + 1; - cur = count < ARRAY_SIZE(log->entry) && !log->full ? - 0 : count % ARRAY_SIZE(log->entry); - if (count > ARRAY_SIZE(log->entry) || log->full) - count = ARRAY_SIZE(log->entry); - for (i = 0; i < count; i++) { - unsigned int index = cur++ % ARRAY_SIZE(log->entry); +static int binder_failed_transaction_log_show(struct seq_file *m, void *unused) +{ + struct binder_device *device; + struct binder_context *context; - print_binder_transaction_log_entry(m, &log->entry[index]); + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + print_binder_transaction_log(m, + &context->transaction_log_failed); } return 0; } @@ -5609,11 +4408,20 @@ BINDER_DEBUG_ENTRY(state); BINDER_DEBUG_ENTRY(stats); BINDER_DEBUG_ENTRY(transactions); BINDER_DEBUG_ENTRY(transaction_log); +BINDER_DEBUG_ENTRY(failed_transaction_log); + +static void __init free_binder_device(struct binder_device *device) +{ + if (device->context.binder_deferred_workqueue) + destroy_workqueue(device->context.binder_deferred_workqueue); + kfree(device); +} static int __init init_binder_device(const char *name) { int ret; struct binder_device *binder_device; + struct binder_context *context; binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL); if (!binder_device) @@ -5623,34 +4431,65 @@ static int __init init_binder_device(const char *name) binder_device->miscdev.minor = MISC_DYNAMIC_MINOR; binder_device->miscdev.name = name; - binder_device->context.binder_context_mgr_uid = INVALID_UID; - binder_device->context.name = name; - mutex_init(&binder_device->context.context_mgr_node_lock); + context = &binder_device->context; + context->binder_context_mgr_uid = INVALID_UID; + context->name = name; + + mutex_init(&context->binder_main_lock); + mutex_init(&context->binder_deferred_lock); + mutex_init(&context->binder_mmap_lock); + + context->binder_deferred_workqueue = + create_singlethread_workqueue(name); + + if (!context->binder_deferred_workqueue) { + ret = -ENOMEM; + goto err_create_singlethread_workqueue_failed; + } + + INIT_HLIST_HEAD(&context->binder_procs); + INIT_HLIST_HEAD(&context->binder_dead_nodes); + INIT_HLIST_HEAD(&context->binder_deferred_list); + INIT_WORK(&context->deferred_work, binder_deferred_func); ret = misc_register(&binder_device->miscdev); if (ret < 0) { - kfree(binder_device); - return ret; + goto err_misc_register_failed; } hlist_add_head(&binder_device->hlist, &binder_devices); + return ret; + +err_create_singlethread_workqueue_failed: +err_misc_register_failed: + free_binder_device(binder_device); return ret; } static int __init binder_init(void) { - int ret; + int ret = 0; char *device_name, *device_names; struct binder_device *device; struct hlist_node *tmp; - atomic_set(&binder_transaction_log.cur, ~0U); - atomic_set(&binder_transaction_log_failed.cur, ~0U); - binder_deferred_workqueue = create_singlethread_workqueue("binder"); - if (!binder_deferred_workqueue) + /* + * Copy the module_parameter string, because we don't want to + * tokenize it in-place. + */ + device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); + if (!device_names) return -ENOMEM; + strcpy(device_names, binder_devices_param); + + while ((device_name = strsep(&device_names, ","))) { + ret = init_binder_device(device_name); + if (ret) + goto err_init_binder_device_failed; + } + binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); if (binder_debugfs_dir_entry_root) binder_debugfs_dir_entry_proc = debugfs_create_dir("proc", @@ -5675,30 +4514,13 @@ static int __init binder_init(void) debugfs_create_file("transaction_log", S_IRUGO, binder_debugfs_dir_entry_root, - &binder_transaction_log, + NULL, &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", S_IRUGO, binder_debugfs_dir_entry_root, - &binder_transaction_log_failed, - &binder_transaction_log_fops); - } - - /* - * Copy the module_parameter string, because we don't want to - * tokenize it in-place. - */ - device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); - if (!device_names) { - ret = -ENOMEM; - goto err_alloc_device_names_failed; - } - strcpy(device_names, binder_devices_param); - - while ((device_name = strsep(&device_names, ","))) { - ret = init_binder_device(device_name); - if (ret) - goto err_init_binder_device_failed; + NULL, + &binder_failed_transaction_log_fops); } return ret; @@ -5707,12 +4529,8 @@ err_init_binder_device_failed: hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) { misc_deregister(&device->miscdev); hlist_del(&device->hlist); - kfree(device); + free_binder_device(device); } -err_alloc_device_names_failed: - debugfs_remove_recursive(binder_debugfs_dir_entry_root); - - destroy_workqueue(binder_deferred_workqueue); return ret; } diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h index 7967db16ba5a653d898c097fd0323a23ec918bc0..7f20f3dc83690cad36cfa82c2a946384a8c30bb8 100644 --- a/drivers/android/binder_trace.h +++ b/drivers/android/binder_trace.h @@ -23,8 +23,7 @@ struct binder_buffer; struct binder_node; struct binder_proc; -struct binder_alloc; -struct binder_ref_data; +struct binder_ref; struct binder_thread; struct binder_transaction; @@ -147,8 +146,8 @@ TRACE_EVENT(binder_transaction_received, TRACE_EVENT(binder_transaction_node_to_ref, TP_PROTO(struct binder_transaction *t, struct binder_node *node, - struct binder_ref_data *rdata), - TP_ARGS(t, node, rdata), + struct binder_ref *ref), + TP_ARGS(t, node, ref), TP_STRUCT__entry( __field(int, debug_id) @@ -161,8 +160,8 @@ TRACE_EVENT(binder_transaction_node_to_ref, __entry->debug_id = t->debug_id; __entry->node_debug_id = node->debug_id; __entry->node_ptr = node->ptr; - __entry->ref_debug_id = rdata->debug_id; - __entry->ref_desc = rdata->desc; + __entry->ref_debug_id = ref->debug_id; + __entry->ref_desc = ref->desc; ), TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d", __entry->debug_id, __entry->node_debug_id, @@ -171,9 +170,8 @@ TRACE_EVENT(binder_transaction_node_to_ref, ); TRACE_EVENT(binder_transaction_ref_to_node, - TP_PROTO(struct binder_transaction *t, struct binder_node *node, - struct binder_ref_data *rdata), - TP_ARGS(t, node, rdata), + TP_PROTO(struct binder_transaction *t, struct binder_ref *ref), + TP_ARGS(t, ref), TP_STRUCT__entry( __field(int, debug_id) @@ -184,10 +182,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, ), TP_fast_assign( __entry->debug_id = t->debug_id; - __entry->ref_debug_id = rdata->debug_id; - __entry->ref_desc = rdata->desc; - __entry->node_debug_id = node->debug_id; - __entry->node_ptr = node->ptr; + __entry->ref_debug_id = ref->debug_id; + __entry->ref_desc = ref->desc; + __entry->node_debug_id = ref->node->debug_id; + __entry->node_ptr = ref->node->ptr; ), TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx", __entry->debug_id, __entry->node_debug_id, @@ -196,10 +194,9 @@ TRACE_EVENT(binder_transaction_ref_to_node, ); TRACE_EVENT(binder_transaction_ref_to_ref, - TP_PROTO(struct binder_transaction *t, struct binder_node *node, - struct binder_ref_data *src_ref, - struct binder_ref_data *dest_ref), - TP_ARGS(t, node, src_ref, dest_ref), + TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref, + struct binder_ref *dest_ref), + TP_ARGS(t, src_ref, dest_ref), TP_STRUCT__entry( __field(int, debug_id) @@ -211,7 +208,7 @@ TRACE_EVENT(binder_transaction_ref_to_ref, ), TP_fast_assign( __entry->debug_id = t->debug_id; - __entry->node_debug_id = node->debug_id; + __entry->node_debug_id = src_ref->node->debug_id; __entry->src_ref_debug_id = src_ref->debug_id; __entry->src_ref_desc = src_ref->desc; __entry->dest_ref_debug_id = dest_ref->debug_id; @@ -271,9 +268,9 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, TP_ARGS(buffer)); TRACE_EVENT(binder_update_page_range, - TP_PROTO(struct binder_alloc *alloc, bool allocate, + TP_PROTO(struct binder_proc *proc, bool allocate, void *start, void *end), - TP_ARGS(alloc, allocate, start, end), + TP_ARGS(proc, allocate, start, end), TP_STRUCT__entry( __field(int, proc) __field(bool, allocate) @@ -281,9 +278,9 @@ TRACE_EVENT(binder_update_page_range, __field(size_t, size) ), TP_fast_assign( - __entry->proc = alloc->pid; + __entry->proc = proc->pid; __entry->allocate = allocate; - __entry->offset = start - alloc->buffer; + __entry->offset = start - proc->buffer; __entry->size = end - start; ), TP_printk("proc=%d allocate=%d offset=%zu size=%zu", diff --git a/drivers/base/core.c b/drivers/base/core.c index f3d395bfe8f62005312e6d00f2a5477185421eec..3fa9096b27c2175dd4ce9d0b0cc332b96bed22c9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1116,7 +1116,13 @@ int device_add(struct device *dev) error = dpm_sysfs_add(dev); if (error) goto DPMError; - device_pm_add(dev); + if ((dev->pm_domain) || (dev->type && dev->type->pm) + || (dev->class && (dev->class->pm || dev->class->resume)) + || (dev->bus && (dev->bus->pm || dev->bus->resume)) || + (dev->driver && dev->driver->pm)) { + device_pm_add(dev); + } + if (MAJOR(dev->devt)) { error = device_create_file(dev, &dev_attr_dev); @@ -2099,11 +2105,7 @@ void device_shutdown(void) pm_runtime_get_noresume(dev); pm_runtime_barrier(dev); - if (dev->class && dev->class->shutdown) { - if (initcall_debug) - dev_info(dev, "shutdown\n"); - dev->class->shutdown(dev); - } else if (dev->bus && dev->bus->shutdown) { + if (dev->bus && dev->bus->shutdown) { if (initcall_debug) dev_info(dev, "shutdown\n"); dev->bus->shutdown(dev); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 4bba25e3615af7a26ccdd36bf4f15afab93781ec..a1696e1d199f1a9b9744bbc40da6df86211f8dc5 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -1113,7 +1113,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, timeout = MAX_JIFFY_OFFSET; } - timeout = wait_for_completion_killable_timeout(&buf->completion, + timeout = wait_for_completion_interruptible_timeout(&buf->completion, timeout); if (timeout == -ERESTARTSYS || !timeout) { retval = timeout; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index ae7f3ce90bd2c4133b76eb364c6c46364d29d663..9920916a6220d470f1739f3d17b574a3c4729a92 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -827,7 +827,7 @@ static ssize_t driver_override_store(struct device *dev, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); - char *driver_override, *old, *cp; + char *driver_override, *old = pdev->driver_override, *cp; if (count > PATH_MAX) return -EINVAL; @@ -840,15 +840,12 @@ static ssize_t driver_override_store(struct device *dev, if (cp) *cp = '\0'; - device_lock(dev); - old = pdev->driver_override; if (strlen(driver_override)) { pdev->driver_override = driver_override; } else { kfree(driver_override); pdev->driver_override = NULL; } - device_unlock(dev); kfree(old); @@ -859,12 +856,8 @@ static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); - ssize_t len; - device_lock(dev); - len = sprintf(buf, "%s\n", pdev->driver_override); - device_unlock(dev); - return len; + return sprintf(buf, "%s\n", pdev->driver_override); } static DEVICE_ATTR_RW(driver_override); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 6c5bc3fadfcfc5dda58bb4e48935be753b4233ab..536a75e8d8cbdbbaa14cc60e70725f4d040ca8c1 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -16,6 +16,11 @@ * domain dependencies may differ from the ancestral dependencies that the * subsystem list maintains. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -34,6 +39,10 @@ #include #include #include +#ifdef CONFIG_PM_WAKEUP_TIMES +#include +#include +#endif #include "../base.h" #include "power.h" @@ -57,6 +66,11 @@ static LIST_HEAD(dpm_late_early_list); static LIST_HEAD(dpm_noirq_list); struct suspend_stats suspend_stats; +#ifdef CONFIG_PM_WAKEUP_TIMES +struct suspend_stats_queue suspend_stats_queue; +static ktime_t suspend_start_time; +static ktime_t resume_start_time; +#endif static DEFINE_MUTEX(dpm_list_mtx); static pm_message_t pm_transition; @@ -162,6 +176,12 @@ void device_pm_move_before(struct device *deva, struct device *devb) pr_debug("PM: Moving %s:%s before %s:%s\n", deva->bus ? deva->bus->name : "No Bus", dev_name(deva), devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); + if (!((devb->pm_domain) || (devb->type && devb->type->pm) + || (devb->class && (devb->class->pm || devb->class->resume)) + || (devb->bus && (devb->bus->pm || devb->bus->resume)) || + (devb->driver && devb->driver->pm))) { + device_pm_add(devb); + } /* Delete deva from dpm_list and reinsert before devb. */ list_move_tail(&deva->power.entry, &devb->power.entry); } @@ -176,6 +196,12 @@ void device_pm_move_after(struct device *deva, struct device *devb) pr_debug("PM: Moving %s:%s after %s:%s\n", deva->bus ? deva->bus->name : "No Bus", dev_name(deva), devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); + if (!((devb->pm_domain) || (devb->type && devb->type->pm) + || (devb->class && (devb->class->pm || devb->class->resume)) + || (devb->bus && (devb->bus->pm || devb->bus->resume)) || + (devb->driver && devb->driver->pm))) { + device_pm_add(devb); + } /* Delete deva from dpm_list and reinsert after devb. */ list_move(&deva->power.entry, &devb->power.entry); } @@ -376,6 +402,100 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); } +#ifdef CONFIG_PM_WAKEUP_TIMES +void dpm_log_start_time(pm_message_t state) +{ + switch (state.event) { + case PM_EVENT_RESUME: + resume_start_time = ktime_get_boottime(); + break; + case PM_EVENT_SUSPEND: + suspend_start_time = ktime_get_boottime(); + break; + default: + break; + } +} +EXPORT_SYMBOL_GPL(dpm_log_start_time); + +void dpm_log_wakeup_stats(pm_message_t state) +{ + ktime_t *start_time, *avg_time, end_time, duration, prev_duration, sum; + struct stats_wakeup_time *min_time, *max_time, *last_time, prev; + u64 avg_ns; + char buf[32] = {0}; + unsigned int nr = 0; + + switch (state.event) { + case PM_EVENT_RESUME: + snprintf(buf, sizeof(buf), "%s", "resume time:"); + start_time = &resume_start_time; + min_time = &suspend_stats.resume_min_time; + max_time = &suspend_stats.resume_max_time; + last_time = &suspend_stats.resume_last_time; + avg_time = &suspend_stats.resume_avg_time; + break; + case PM_EVENT_SUSPEND: + snprintf(buf, sizeof(buf), "%s", "suspend time:"); + start_time = &suspend_start_time; + min_time = &suspend_stats.suspend_min_time; + max_time = &suspend_stats.suspend_max_time; + last_time = &suspend_stats.suspend_last_time; + avg_time = &suspend_stats.suspend_avg_time; + break; + default: + return; + } + + if (!ktime_to_ns(*start_time)) + return; + + /* Calculate duration and update last time */ + end_time = ktime_get_boottime(); + prev = *last_time; + prev_duration = ktime_sub(prev.end, prev.start); + last_time->end = end_time; + last_time->start = *start_time; + duration = ktime_sub(end_time, *start_time); + + /* Update max time */ + if (ktime_compare(duration, + ktime_sub(max_time->end, max_time->start)) > 0) + *max_time = *last_time; + + /* Update min time */ + if (!ktime_to_ns(ktime_sub(min_time->end, min_time->start))) + *min_time = *last_time; + + if (ktime_compare(duration, + ktime_sub(min_time->end, min_time->start)) < 0) + *min_time = *last_time; + + /* Compute the avg of current, previous and previous average times */ + if (ktime_to_ns(prev_duration)) + nr++; + + if (ktime_to_ns(*avg_time)) + nr++; + + sum = ktime_add(ktime_add(*avg_time, prev_duration), duration); + avg_ns = div_u64(ktime_to_ns(sum), (nr + 1)); + *avg_time = ktime_set(0, avg_ns); + *start_time = ktime_set(0, 0); + + pr_debug("%s\n%s %llums\n%s %llums\n %s %llums\n%s %llums\n", buf, + " min:", + ktime_to_ms(ktime_sub(min_time->end, min_time->start)), + " max:", + ktime_to_ms(ktime_sub(max_time->end, max_time->start)), + " last:", ktime_to_ms(duration), + " avg:", ktime_to_ms(*avg_time)); + suspend_stats_queue.resume_done = 1; + wake_up(&suspend_stats_queue.wait_queue); +} +EXPORT_SYMBOL_GPL(dpm_log_wakeup_stats); +#endif + static int dpm_run_callback(pm_callback_t cb, struct device *dev, pm_message_t state, char *info) { diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 39efa7e6c0c0e80ae38669cfb9974b931ee910b9..a7b46798c81d0452149907e153ae149830fdbceb 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -268,8 +268,6 @@ static ssize_t pm_qos_latency_tolerance_store(struct device *dev, value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; else if (!strcmp(buf, "any") || !strcmp(buf, "any\n")) value = PM_QOS_LATENCY_ANY; - else - return -EINVAL; } ret = dev_pm_qos_update_user_latency_tolerance(dev, value); return ret < 0 ? ret : n; diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 7af116e12e53d359b5a82f7e9bdf145fccc82b80..0e494108c20ccec68abb460ccf2f1853976fb6b9 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -61,8 +61,6 @@ static LIST_HEAD(wakeup_sources); static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue); -DEFINE_STATIC_SRCU(wakeup_srcu); - static struct wakeup_source deleted_ws = { .name = "deleted", .lock = __SPIN_LOCK_UNLOCKED(deleted_ws.lock), @@ -201,7 +199,7 @@ void wakeup_source_remove(struct wakeup_source *ws) spin_lock_irqsave(&events_lock, flags); list_del_rcu(&ws->entry); spin_unlock_irqrestore(&events_lock, flags); - synchronize_srcu(&wakeup_srcu); + synchronize_rcu(); } EXPORT_SYMBOL_GPL(wakeup_source_remove); @@ -333,14 +331,13 @@ void device_wakeup_detach_irq(struct device *dev) void device_wakeup_arm_wake_irqs(void) { struct wakeup_source *ws; - int srcuidx; - srcuidx = srcu_read_lock(&wakeup_srcu); + rcu_read_lock(); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { if (ws->wakeirq) dev_pm_arm_wake_irq(ws->wakeirq); } - srcu_read_unlock(&wakeup_srcu, srcuidx); + rcu_read_unlock(); } /** @@ -351,14 +348,13 @@ void device_wakeup_arm_wake_irqs(void) void device_wakeup_disarm_wake_irqs(void) { struct wakeup_source *ws; - int srcuidx; - srcuidx = srcu_read_lock(&wakeup_srcu); + rcu_read_lock(); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { if (ws->wakeirq) dev_pm_disarm_wake_irq(ws->wakeirq); } - srcu_read_unlock(&wakeup_srcu, srcuidx); + rcu_read_unlock(); } /** @@ -843,10 +839,10 @@ EXPORT_SYMBOL_GPL(pm_get_active_wakeup_sources); void pm_print_active_wakeup_sources(void) { struct wakeup_source *ws; - int srcuidx, active = 0; + int active = 0; struct wakeup_source *last_activity_ws = NULL; - srcuidx = srcu_read_lock(&wakeup_srcu); + rcu_read_lock(); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { if (ws->active) { pr_info("active wakeup source: %s\n", ws->name); @@ -862,7 +858,7 @@ void pm_print_active_wakeup_sources(void) if (!active && last_activity_ws) pr_info("last active wakeup source: %s\n", last_activity_ws->name); - srcu_read_unlock(&wakeup_srcu, srcuidx); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources); @@ -989,9 +985,8 @@ void pm_wakep_autosleep_enabled(bool set) { struct wakeup_source *ws; ktime_t now = ktime_get(); - int srcuidx; - srcuidx = srcu_read_lock(&wakeup_srcu); + rcu_read_lock(); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { spin_lock_irq(&ws->lock); if (ws->autosleep_enabled != set) { @@ -1005,7 +1000,7 @@ void pm_wakep_autosleep_enabled(bool set) } spin_unlock_irq(&ws->lock); } - srcu_read_unlock(&wakeup_srcu, srcuidx); + rcu_read_unlock(); } #endif /* CONFIG_PM_AUTOSLEEP */ @@ -1066,16 +1061,15 @@ static int print_wakeup_source_stats(struct seq_file *m, static int wakeup_sources_stats_show(struct seq_file *m, void *unused) { struct wakeup_source *ws; - int srcuidx; seq_puts(m, "name\t\t\t\t\tactive_count\tevent_count\twakeup_count\t" "expire_count\tactive_since\ttotal_time\tmax_time\t" "last_change\tprevent_suspend_time\n"); - srcuidx = srcu_read_lock(&wakeup_srcu); + rcu_read_lock(); list_for_each_entry_rcu(ws, &wakeup_sources, entry) print_wakeup_source_stats(m, ws); - srcu_read_unlock(&wakeup_srcu, srcuidx); + rcu_read_unlock(); print_wakeup_source_stats(m, &deleted_ws); diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 61cdbaa3c09a5e0d1d10307c16f6be19b52bc812..09a0cade7dbee4f39a49780a59340ad6be930ca5 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -9,6 +9,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _REGMAP_INTERNAL_H #define _REGMAP_INTERNAL_H diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 576b5facdf4319d2b0a6960b62b0637da566500e..4b88a381d02af27c7b1a9792199c907147807aac 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -9,6 +9,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig index 386ba3d1a6ee8aed4a9c9885f07c408dfa3bff4b..4831d0a4f3523740ddd8b96f829c2ba22733f5af 100644 --- a/drivers/block/zram/Kconfig +++ b/drivers/block/zram/Kconfig @@ -1,6 +1,7 @@ config ZRAM tristate "Compressed RAM block device support" - depends on BLOCK && SYSFS && ZSMALLOC + depends on BLOCK && SYSFS + select ZPOOL select LZO_COMPRESS select LZO_DECOMPRESS default n diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c index c53617752b93cc3976f764e19cc436b5cb66cdcf..b51a816d766bb31cf8f8615535fe2435eda49f1e 100644 --- a/drivers/block/zram/zcomp.c +++ b/drivers/block/zram/zcomp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "zcomp.h" #include "zcomp_lzo.h" @@ -20,29 +21,6 @@ #include "zcomp_lz4.h" #endif -/* - * single zcomp_strm backend - */ -struct zcomp_strm_single { - struct mutex strm_lock; - struct zcomp_strm *zstrm; -}; - -/* - * multi zcomp_strm backend - */ -struct zcomp_strm_multi { - /* protect strm list */ - spinlock_t strm_lock; - /* max possible number of zstrm streams */ - int max_strm; - /* number of available zstrm streams */ - int avail_strm; - /* list of available strms */ - struct list_head idle_strm; - wait_queue_head_t strm_wait; -}; - static struct zcomp_backend *backends[] = { &zcomp_lzo, #ifdef CONFIG_ZRAM_LZ4_COMPRESS @@ -74,18 +52,18 @@ static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm) * allocate new zcomp_strm structure with ->private initialized by * backend, return NULL on error */ -static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp) +static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp, gfp_t flags) { - struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_NOIO); + struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), flags); if (!zstrm) return NULL; - zstrm->private = comp->backend->create(); + zstrm->private = comp->backend->create(flags); /* * allocate 2 pages. 1 for compressed data, plus 1 extra for the * case when compressed size is larger than the original one */ - zstrm->buffer = (void *)__get_free_pages(GFP_NOIO | __GFP_ZERO, 1); + zstrm->buffer = (void *)__get_free_pages(flags | __GFP_ZERO, 1); if (!zstrm->private || !zstrm->buffer) { zcomp_strm_free(comp, zstrm); zstrm = NULL; @@ -93,180 +71,6 @@ static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp) return zstrm; } -/* - * get idle zcomp_strm or wait until other process release - * (zcomp_strm_release()) one for us - */ -static struct zcomp_strm *zcomp_strm_multi_find(struct zcomp *comp) -{ - struct zcomp_strm_multi *zs = comp->stream; - struct zcomp_strm *zstrm; - - while (1) { - spin_lock(&zs->strm_lock); - if (!list_empty(&zs->idle_strm)) { - zstrm = list_entry(zs->idle_strm.next, - struct zcomp_strm, list); - list_del(&zstrm->list); - spin_unlock(&zs->strm_lock); - return zstrm; - } - /* zstrm streams limit reached, wait for idle stream */ - if (zs->avail_strm >= zs->max_strm) { - spin_unlock(&zs->strm_lock); - wait_event(zs->strm_wait, !list_empty(&zs->idle_strm)); - continue; - } - /* allocate new zstrm stream */ - zs->avail_strm++; - spin_unlock(&zs->strm_lock); - - zstrm = zcomp_strm_alloc(comp); - if (!zstrm) { - spin_lock(&zs->strm_lock); - zs->avail_strm--; - spin_unlock(&zs->strm_lock); - wait_event(zs->strm_wait, !list_empty(&zs->idle_strm)); - continue; - } - break; - } - return zstrm; -} - -/* add stream back to idle list and wake up waiter or free the stream */ -static void zcomp_strm_multi_release(struct zcomp *comp, struct zcomp_strm *zstrm) -{ - struct zcomp_strm_multi *zs = comp->stream; - - spin_lock(&zs->strm_lock); - if (zs->avail_strm <= zs->max_strm) { - list_add(&zstrm->list, &zs->idle_strm); - spin_unlock(&zs->strm_lock); - wake_up(&zs->strm_wait); - return; - } - - zs->avail_strm--; - spin_unlock(&zs->strm_lock); - zcomp_strm_free(comp, zstrm); -} - -/* change max_strm limit */ -static bool zcomp_strm_multi_set_max_streams(struct zcomp *comp, int num_strm) -{ - struct zcomp_strm_multi *zs = comp->stream; - struct zcomp_strm *zstrm; - - spin_lock(&zs->strm_lock); - zs->max_strm = num_strm; - /* - * if user has lowered the limit and there are idle streams, - * immediately free as much streams (and memory) as we can. - */ - while (zs->avail_strm > num_strm && !list_empty(&zs->idle_strm)) { - zstrm = list_entry(zs->idle_strm.next, - struct zcomp_strm, list); - list_del(&zstrm->list); - zcomp_strm_free(comp, zstrm); - zs->avail_strm--; - } - spin_unlock(&zs->strm_lock); - return true; -} - -static void zcomp_strm_multi_destroy(struct zcomp *comp) -{ - struct zcomp_strm_multi *zs = comp->stream; - struct zcomp_strm *zstrm; - - while (!list_empty(&zs->idle_strm)) { - zstrm = list_entry(zs->idle_strm.next, - struct zcomp_strm, list); - list_del(&zstrm->list); - zcomp_strm_free(comp, zstrm); - } - kfree(zs); -} - -static int zcomp_strm_multi_create(struct zcomp *comp, int max_strm) -{ - struct zcomp_strm *zstrm; - struct zcomp_strm_multi *zs; - - comp->destroy = zcomp_strm_multi_destroy; - comp->strm_find = zcomp_strm_multi_find; - comp->strm_release = zcomp_strm_multi_release; - comp->set_max_streams = zcomp_strm_multi_set_max_streams; - zs = kmalloc(sizeof(struct zcomp_strm_multi), GFP_KERNEL); - if (!zs) - return -ENOMEM; - - comp->stream = zs; - spin_lock_init(&zs->strm_lock); - INIT_LIST_HEAD(&zs->idle_strm); - init_waitqueue_head(&zs->strm_wait); - zs->max_strm = max_strm; - zs->avail_strm = 1; - - zstrm = zcomp_strm_alloc(comp); - if (!zstrm) { - kfree(zs); - return -ENOMEM; - } - list_add(&zstrm->list, &zs->idle_strm); - return 0; -} - -static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp) -{ - struct zcomp_strm_single *zs = comp->stream; - mutex_lock(&zs->strm_lock); - return zs->zstrm; -} - -static void zcomp_strm_single_release(struct zcomp *comp, - struct zcomp_strm *zstrm) -{ - struct zcomp_strm_single *zs = comp->stream; - mutex_unlock(&zs->strm_lock); -} - -static bool zcomp_strm_single_set_max_streams(struct zcomp *comp, int num_strm) -{ - /* zcomp_strm_single support only max_comp_streams == 1 */ - return false; -} - -static void zcomp_strm_single_destroy(struct zcomp *comp) -{ - struct zcomp_strm_single *zs = comp->stream; - zcomp_strm_free(comp, zs->zstrm); - kfree(zs); -} - -static int zcomp_strm_single_create(struct zcomp *comp) -{ - struct zcomp_strm_single *zs; - - comp->destroy = zcomp_strm_single_destroy; - comp->strm_find = zcomp_strm_single_find; - comp->strm_release = zcomp_strm_single_release; - comp->set_max_streams = zcomp_strm_single_set_max_streams; - zs = kmalloc(sizeof(struct zcomp_strm_single), GFP_KERNEL); - if (!zs) - return -ENOMEM; - - comp->stream = zs; - mutex_init(&zs->strm_lock); - zs->zstrm = zcomp_strm_alloc(comp); - if (!zs->zstrm) { - kfree(zs); - return -ENOMEM; - } - return 0; -} - /* show available compressors */ ssize_t zcomp_available_show(const char *comp, char *buf) { @@ -291,19 +95,14 @@ bool zcomp_available_algorithm(const char *comp) return find_backend(comp) != NULL; } -bool zcomp_set_max_streams(struct zcomp *comp, int num_strm) -{ - return comp->set_max_streams(comp, num_strm); -} - struct zcomp_strm *zcomp_strm_find(struct zcomp *comp) { - return comp->strm_find(comp); + return *get_cpu_ptr(comp->stream); } void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm) { - comp->strm_release(comp, zstrm); + put_cpu_ptr(comp->stream); } int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm, @@ -319,9 +118,83 @@ int zcomp_decompress(struct zcomp *comp, const unsigned char *src, return comp->backend->decompress(src, src_len, dst); } +static int __zcomp_cpu_notifier(struct zcomp *comp, + unsigned long action, unsigned long cpu) +{ + struct zcomp_strm *zstrm; + + switch (action) { + case CPU_UP_PREPARE: + if (WARN_ON(*per_cpu_ptr(comp->stream, cpu))) + break; + zstrm = zcomp_strm_alloc(comp, GFP_KERNEL); + if (IS_ERR_OR_NULL(zstrm)) { + pr_err("Can't allocate a compression stream\n"); + return NOTIFY_BAD; + } + *per_cpu_ptr(comp->stream, cpu) = zstrm; + break; + case CPU_DEAD: + case CPU_UP_CANCELED: + zstrm = *per_cpu_ptr(comp->stream, cpu); + if (!IS_ERR_OR_NULL(zstrm)) + zcomp_strm_free(comp, zstrm); + *per_cpu_ptr(comp->stream, cpu) = NULL; + break; + default: + break; + } + return NOTIFY_OK; +} + +static int zcomp_cpu_notifier(struct notifier_block *nb, + unsigned long action, void *pcpu) +{ + unsigned long cpu = (unsigned long)pcpu; + struct zcomp *comp = container_of(nb, typeof(*comp), notifier); + + return __zcomp_cpu_notifier(comp, action, cpu); +} + +static int zcomp_init(struct zcomp *comp) +{ + unsigned long cpu; + int ret; + + comp->notifier.notifier_call = zcomp_cpu_notifier; + + comp->stream = alloc_percpu(struct zcomp_strm *); + if (!comp->stream) + return -ENOMEM; + + cpu_notifier_register_begin(); + for_each_online_cpu(cpu) { + ret = __zcomp_cpu_notifier(comp, CPU_UP_PREPARE, cpu); + if (ret == NOTIFY_BAD) + goto cleanup; + } + __register_cpu_notifier(&comp->notifier); + cpu_notifier_register_done(); + return 0; + +cleanup: + for_each_online_cpu(cpu) + __zcomp_cpu_notifier(comp, CPU_UP_CANCELED, cpu); + cpu_notifier_register_done(); + return -ENOMEM; +} + void zcomp_destroy(struct zcomp *comp) { - comp->destroy(comp); + unsigned long cpu; + + cpu_notifier_register_begin(); + for_each_online_cpu(cpu) + __zcomp_cpu_notifier(comp, CPU_UP_CANCELED, cpu); + __unregister_cpu_notifier(&comp->notifier); + cpu_notifier_register_done(); + + free_percpu(comp->stream); kfree(comp); } @@ -331,9 +204,9 @@ void zcomp_destroy(struct zcomp *comp) * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL) * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in * case of allocation error, or any other error potentially - * returned by functions zcomp_strm_{multi,single}_create. + * returned by zcomp_init(). */ -struct zcomp *zcomp_create(const char *compress, int max_strm) +struct zcomp *zcomp_create(const char *compress) { struct zcomp *comp; struct zcomp_backend *backend; @@ -348,10 +221,7 @@ struct zcomp *zcomp_create(const char *compress, int max_strm) return ERR_PTR(-ENOMEM); comp->backend = backend; - if (max_strm > 1) - error = zcomp_strm_multi_create(comp, max_strm); - else - error = zcomp_strm_single_create(comp); + error = zcomp_init(comp); if (error) { kfree(comp); return ERR_PTR(error); diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h index 46e2b9f8f1f0e3ec684736305c4d8a1ab8de0c97..ffd88cb747feefb7fb04a467e4cd2456e49249b6 100644 --- a/drivers/block/zram/zcomp.h +++ b/drivers/block/zram/zcomp.h @@ -10,8 +10,6 @@ #ifndef _ZCOMP_H_ #define _ZCOMP_H_ -#include - struct zcomp_strm { /* compression/decompression buffer */ void *buffer; @@ -21,8 +19,6 @@ struct zcomp_strm { * working memory) */ void *private; - /* used in multi stream backend, protected by backend strm_lock */ - struct list_head list; }; /* static compression backend */ @@ -33,7 +29,7 @@ struct zcomp_backend { int (*decompress)(const unsigned char *src, size_t src_len, unsigned char *dst); - void *(*create)(void); + void *(*create)(gfp_t flags); void (*destroy)(void *private); const char *name; @@ -41,19 +37,15 @@ struct zcomp_backend { /* dynamic per-device compression frontend */ struct zcomp { - void *stream; + struct zcomp_strm * __percpu *stream; struct zcomp_backend *backend; - - struct zcomp_strm *(*strm_find)(struct zcomp *comp); - void (*strm_release)(struct zcomp *comp, struct zcomp_strm *zstrm); - bool (*set_max_streams)(struct zcomp *comp, int num_strm); - void (*destroy)(struct zcomp *comp); + struct notifier_block notifier; }; ssize_t zcomp_available_show(const char *comp, char *buf); bool zcomp_available_algorithm(const char *comp); -struct zcomp *zcomp_create(const char *comp, int max_strm); +struct zcomp *zcomp_create(const char *comp); void zcomp_destroy(struct zcomp *comp); struct zcomp_strm *zcomp_strm_find(struct zcomp *comp); diff --git a/drivers/block/zram/zcomp_lz4.c b/drivers/block/zram/zcomp_lz4.c index dd6083124276fa107717112cb273648887f1d52e..dc2338d5258c171f55ac5d4d3576fbb9465c4643 100644 --- a/drivers/block/zram/zcomp_lz4.c +++ b/drivers/block/zram/zcomp_lz4.c @@ -15,24 +15,14 @@ #include "zcomp_lz4.h" -static void *zcomp_lz4_create(void) +static void *zcomp_lz4_create(gfp_t flags) { void *ret; - /* - * This function can be called in swapout/fs write path - * so we can't use GFP_FS|IO. And it assumes we already - * have at least one stream in zram initialization so we - * don't do best effort to allocate more stream in here. - * A default stream will work well without further multiple - * streams. That's why we use NORETRY | NOWARN. - */ - ret = kzalloc(LZ4_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY | - __GFP_NOWARN); + ret = kzalloc(LZ4_MEM_COMPRESS, flags); if (!ret) ret = __vmalloc(LZ4_MEM_COMPRESS, - GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN | - __GFP_ZERO | __GFP_HIGHMEM, + flags | __GFP_ZERO | __GFP_HIGHMEM, PAGE_KERNEL); return ret; } diff --git a/drivers/block/zram/zcomp_lzo.c b/drivers/block/zram/zcomp_lzo.c index edc549920fa069478e24edf9fa4e416fdbb8adf6..0ab6fce8abe4782994c7f425300a6cce1e21afaf 100644 --- a/drivers/block/zram/zcomp_lzo.c +++ b/drivers/block/zram/zcomp_lzo.c @@ -15,24 +15,14 @@ #include "zcomp_lzo.h" -static void *lzo_create(void) +static void *lzo_create(gfp_t flags) { void *ret; - /* - * This function can be called in swapout/fs write path - * so we can't use GFP_FS|IO. And it assumes we already - * have at least one stream in zram initialization so we - * don't do best effort to allocate more stream in here. - * A default stream will work well without further multiple - * streams. That's why we use NORETRY | NOWARN. - */ - ret = kzalloc(LZO1X_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY | - __GFP_NOWARN); + ret = kzalloc(LZO1X_MEM_COMPRESS, flags); if (!ret) ret = __vmalloc(LZO1X_MEM_COMPRESS, - GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN | - __GFP_ZERO | __GFP_HIGHMEM, + flags | __GFP_ZERO | __GFP_HIGHMEM, PAGE_KERNEL); return ret; } diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index c5a2057ef6681de751aea3825de12e5e7be6cac4..a44d255218a8804c38b2e2bac8e6b33ce49b1f75 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -11,6 +11,11 @@ * Released under the terms of GNU General Public License Version 2.0 * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define KMSG_COMPONENT "zram" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt @@ -39,6 +44,8 @@ static DEFINE_MUTEX(zram_index_mutex); static int zram_major; static const char *default_compressor = "lzo"; +#define BACKEND_PARAM_BUF_SIZE 32 +static char backend_param_buf[BACKEND_PARAM_BUF_SIZE]; /* * We don't need to see memory allocation errors more than once every 1 @@ -235,11 +242,11 @@ static ssize_t mem_used_total_show(struct device *dev, down_read(&zram->init_lock); if (init_done(zram)) { struct zram_meta *meta = zram->meta; - val = zs_get_total_pages(meta->mem_pool); + val = zpool_get_total_size(meta->mem_pool); } up_read(&zram->init_lock); - return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT); + return scnprintf(buf, PAGE_SIZE, "%llu\n", val); } static ssize_t mem_limit_show(struct device *dev, @@ -304,53 +311,32 @@ static ssize_t mem_used_max_store(struct device *dev, if (init_done(zram)) { struct zram_meta *meta = zram->meta; atomic_long_set(&zram->stats.max_used_pages, - zs_get_total_pages(meta->mem_pool)); + zpool_get_total_size(meta->mem_pool) >> PAGE_SHIFT); } up_read(&zram->init_lock); return len; } +/* + * We switched to per-cpu streams and this attr is not needed anymore. + * However, we will keep it around for some time, because: + * a) we may revert per-cpu streams in the future + * b) it's visible to user space and we need to follow our 2 years + * retirement rule; but we already have a number of 'soon to be + * altered' attrs, so max_comp_streams need to wait for the next + * layoff cycle. + */ static ssize_t max_comp_streams_show(struct device *dev, struct device_attribute *attr, char *buf) { - int val; - struct zram *zram = dev_to_zram(dev); - - down_read(&zram->init_lock); - val = zram->max_comp_streams; - up_read(&zram->init_lock); - - return scnprintf(buf, PAGE_SIZE, "%d\n", val); + return scnprintf(buf, PAGE_SIZE, "%d\n", num_online_cpus()); } static ssize_t max_comp_streams_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - int num; - struct zram *zram = dev_to_zram(dev); - int ret; - - ret = kstrtoint(buf, 0, &num); - if (ret < 0) - return ret; - if (num < 1) - return -EINVAL; - - down_write(&zram->init_lock); - if (init_done(zram)) { - if (!zcomp_set_max_streams(zram->comp, num)) { - pr_info("Cannot change max compression streams\n"); - ret = -EINVAL; - goto out; - } - } - - zram->max_comp_streams = num; - ret = len; -out: - up_write(&zram->init_lock); - return ret; + return len; } static ssize_t comp_algorithm_show(struct device *dev, @@ -405,7 +391,7 @@ static ssize_t compact_store(struct device *dev, } meta = zram->meta; - zs_compact(meta->mem_pool); + zpool_compact(meta->mem_pool); up_read(&zram->init_lock); return len; @@ -433,18 +419,13 @@ static ssize_t mm_stat_show(struct device *dev, struct device_attribute *attr, char *buf) { struct zram *zram = dev_to_zram(dev); - struct zs_pool_stats pool_stats; u64 orig_size, mem_used = 0; long max_used; ssize_t ret; - memset(&pool_stats, 0x00, sizeof(struct zs_pool_stats)); - down_read(&zram->init_lock); - if (init_done(zram)) { - mem_used = zs_get_total_pages(zram->meta->mem_pool); - zs_pool_stats(zram->meta->mem_pool, &pool_stats); - } + if (init_done(zram)) + mem_used = zpool_get_total_size(zram->meta->mem_pool); orig_size = atomic64_read(&zram->stats.pages_stored); max_used = atomic_long_read(&zram->stats.max_used_pages); @@ -453,11 +434,11 @@ static ssize_t mm_stat_show(struct device *dev, "%8llu %8llu %8llu %8lu %8ld %8llu %8lu\n", orig_size << PAGE_SHIFT, (u64)atomic64_read(&zram->stats.compr_data_size), - mem_used << PAGE_SHIFT, + mem_used, zram->limit_pages << PAGE_SHIFT, max_used << PAGE_SHIFT, (u64)atomic64_read(&zram->stats.zero_pages), - pool_stats.pages_compacted); + zpool_get_num_compacted(zram->meta->mem_pool)); up_read(&zram->init_lock); return ret; @@ -498,10 +479,10 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize) if (!handle) continue; - zs_free(meta->mem_pool, handle); + zpool_free(meta->mem_pool, handle); } - zs_destroy_pool(meta->mem_pool); + zpool_destroy_pool(meta->mem_pool); vfree(meta->table); kfree(meta); } @@ -510,6 +491,7 @@ static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize) { size_t num_pages; struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL); + char *backend; if (!meta) return NULL; @@ -521,7 +503,9 @@ static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize) goto out_error; } - meta->mem_pool = zs_create_pool(pool_name); + backend = strlen(backend_param_buf) ? backend_param_buf : "zsmalloc"; + meta->mem_pool = zpool_create_pool(backend, pool_name, + GFP_NOIO, NULL); if (!meta->mem_pool) { pr_err("Error creating memory pool\n"); goto out_error; @@ -557,7 +541,7 @@ static void zram_free_page(struct zram *zram, size_t index) return; } - zs_free(meta->mem_pool, handle); + zpool_free(meta->mem_pool, handle); atomic64_sub(zram_get_obj_size(meta, index), &zram->stats.compr_data_size); @@ -585,12 +569,12 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index) return 0; } - cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO); + cmem = zpool_map_handle(meta->mem_pool, handle, ZPOOL_MM_RO); if (size == PAGE_SIZE) memcpy(mem, cmem, PAGE_SIZE); else ret = zcomp_decompress(zram->comp, cmem, size, mem); - zs_unmap_object(meta->mem_pool, handle); + zpool_unmap_handle(meta->mem_pool, handle); bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); /* Should NEVER happen. Return bio error if it does. */ @@ -657,13 +641,12 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, { int ret = 0; size_t clen; - unsigned long handle; + unsigned long handle = 0; struct page *page; unsigned char *user_mem, *cmem, *src, *uncmem = NULL; struct zram_meta *meta = zram->meta; struct zcomp_strm *zstrm = NULL; unsigned long alloced_pages; - static unsigned long zram_rs_time; page = bvec->bv_page; if (is_partial_io(bvec)) { @@ -681,9 +664,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, goto out; } - zstrm = zcomp_strm_find(zram->comp); +compress_again: user_mem = kmap_atomic(page); - if (is_partial_io(bvec)) { memcpy(uncmem + offset, user_mem + bvec->bv_offset, bvec->bv_len); @@ -707,6 +689,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, goto out; } + zstrm = zcomp_strm_find(zram->comp); ret = zcomp_compress(zram->comp, zstrm, uncmem, &clen); if (!is_partial_io(bvec)) { kunmap_atomic(user_mem); @@ -718,6 +701,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, pr_err("Compression failed! err=%d\n", ret); goto out; } + src = zstrm->buffer; if (unlikely(clen > max_zpage_size)) { clen = PAGE_SIZE; @@ -725,28 +709,46 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, src = uncmem; } - handle = zs_malloc(meta->mem_pool, clen, GFP_NOIO | __GFP_HIGHMEM | - __GFP_MOVABLE); - if (!handle) { - if (printk_timed_ratelimit(&zram_rs_time, - ALLOC_ERROR_LOG_RATE_MS)) - pr_info("Error allocating memory for compressed page: %u, size=%zu\n", - index, clen); + /* + * handle allocation has 2 paths: + * a) fast path is executed with preemption disabled (for + * per-cpu streams) and has __GFP_DIRECT_RECLAIM bit clear, + * since we can't sleep; + * b) slow path enables preemption and attempts to allocate + * the page with __GFP_DIRECT_RECLAIM bit set. we have to + * put per-cpu compression stream and, thus, to re-do + * the compression once handle is allocated. + * + * if we have a 'non-null' handle here then we are coming + * from the slow path and handle has already been allocated. + */ + if (!handle) + ret = zpool_malloc(meta->mem_pool, clen, + __GFP_KSWAPD_RECLAIM | __GFP_NOWARN, &handle); + if (ret < 0) { + zcomp_strm_release(zram->comp, zstrm); + zstrm = NULL; + + ret = zpool_malloc(meta->mem_pool, clen, + GFP_NOIO, &handle); + if (ret == 0) + goto compress_again; + pr_err("Error allocating memory for compressed page: %u, size=%zu\n", + index, clen); ret = -ENOMEM; goto out; } - alloced_pages = zs_get_total_pages(meta->mem_pool); + alloced_pages = zpool_get_total_size(meta->mem_pool) >> PAGE_SHIFT; update_used_max(zram, alloced_pages); - if (zram->limit_pages && alloced_pages > zram->limit_pages) { - zs_free(meta->mem_pool, handle); + zpool_free(meta->mem_pool, handle); ret = -ENOMEM; goto out; } - cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO); + cmem = zpool_map_handle(meta->mem_pool, handle, ZPOOL_MM_WO); if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) { src = kmap_atomic(page); @@ -758,7 +760,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, zcomp_strm_release(zram->comp, zstrm); zstrm = NULL; - zs_unmap_object(meta->mem_pool, handle); + zpool_unmap_handle(meta->mem_pool, handle); /* * Free memory associated with this sector @@ -1021,7 +1023,6 @@ static void zram_reset_device(struct zram *zram) /* Reset stats */ memset(&zram->stats, 0, sizeof(zram->stats)); zram->disksize = 0; - zram->max_comp_streams = 1; set_capacity(zram->disk, 0); part_stat_set_all(&zram->disk->part0, 0); @@ -1050,7 +1051,7 @@ static ssize_t disksize_store(struct device *dev, if (!meta) return -ENOMEM; - comp = zcomp_create(zram->compressor, zram->max_comp_streams); + comp = zcomp_create(zram->compressor); if (IS_ERR(comp)) { pr_err("Cannot initialise %s compressing backend\n", zram->compressor); @@ -1286,7 +1287,6 @@ static int zram_add(void) } strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor)); zram->meta = NULL; - zram->max_comp_streams = 1; pr_info("Added device: %s\n", zram->disk->disk_name); return device_id; @@ -1466,6 +1466,8 @@ module_exit(zram_exit); module_param(num_devices, uint, 0); MODULE_PARM_DESC(num_devices, "Number of pre-created zram devices"); +module_param_string(backend, backend_param_buf, BACKEND_PARAM_BUF_SIZE, 0); +MODULE_PARM_DESC(backend, "Compression storage (backend) name"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Nitin Gupta "); diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index 8e92339686d7467584220ff1805002953d5e6621..f9a4c8b6bedc2f68bce970b35472ccebf6c0553f 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -11,12 +11,17 @@ * Released under the terms of GNU General Public License Version 2.0 * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _ZRAM_DRV_H_ #define _ZRAM_DRV_H_ #include -#include +#include #include "zcomp.h" @@ -89,7 +94,7 @@ struct zram_stats { struct zram_meta { struct zram_table_entry *table; - struct zs_pool *mem_pool; + struct zpool *mem_pool; }; struct zram { @@ -102,7 +107,6 @@ struct zram { * the number of pages zram can consume for storing compressed data */ unsigned long limit_pages; - int max_comp_streams; struct zram_stats stats; atomic_t refcount; /* refcount for zram_meta */ diff --git a/drivers/bluetooth/btfm_slim.c b/drivers/bluetooth/btfm_slim.c index 0a61186167ba554e4402e75034260526f58a39c6..969f755f5dc4cc8e2be69ff5ee07b3f9953d6ccf 100644 --- a/drivers/bluetooth/btfm_slim.c +++ b/drivers/bluetooth/btfm_slim.c @@ -155,22 +155,23 @@ int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, rxport, 1); if (ret < 0) { BTFMSLIM_ERR("vendor_port_en failed ret[%d]", - ret); + ret); goto error; } } if (rxport) { BTFMSLIM_INFO("slim_connect_sink(port: %d, ch: %d)", - ch->port, ch->ch); + ch->port, ch->ch); /* Connect Port with channel given by Machine driver*/ ret = slim_connect_sink(btfmslim->slim_pgd, &ch->port_hdl, 1, ch->ch_hdl); if (ret < 0) { BTFMSLIM_ERR("slim_connect_sink failed ret[%d]", - ret); + ret); goto remove_channel; } + } else { BTFMSLIM_INFO("slim_connect_src(port: %d, ch: %d)", ch->port, ch->ch); @@ -179,7 +180,7 @@ int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, ch->ch_hdl); if (ret < 0) { BTFMSLIM_ERR("slim_connect_src failed ret[%d]", - ret); + ret); goto remove_channel; } } @@ -189,7 +190,6 @@ int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, BTFMSLIM_INFO( "port: %d, ch: %d, grp: %d, ch->grph: 0x%x, ch_hdl: 0x%x", chan->port, chan->ch, grp, chan->grph, chan->ch_hdl); - ret = slim_control_ch(btfmslim->slim_pgd, (grp ? chan->grph : chan->ch_hdl), SLIM_CH_ACTIVATE, true); if (ret < 0) { @@ -220,7 +220,6 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, BTFMSLIM_INFO("port:%d, grp: %d, ch->grph:0x%x, ch->ch_hdl:0x%x ", ch->port, grp, ch->grph, ch->ch_hdl); - /* Remove the channel immediately*/ ret = slim_control_ch(btfmslim->slim_pgd, (grp ? ch->grph : ch->ch_hdl), SLIM_CH_REMOVE, true); @@ -234,6 +233,7 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, goto error; } } + /* Disable port through registration setting */ for (i = 0; i < nchan; i++, ch++) { if (btfmslim->vendor_port_en) { @@ -246,11 +246,9 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, } } } - error: return ret; } - static int btfm_slim_get_logical_addr(struct slim_device *slim) { int ret = 0; diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c index 035e8d9fb5fd6aa178a742ad2993f8cd55cf0b2c..96be0e2f9183fba04b424da45655ff9311e72c61 100644 --- a/drivers/bluetooth/btfm_slim_codec.c +++ b/drivers/bluetooth/btfm_slim_codec.c @@ -118,6 +118,9 @@ static void btfm_slim_dai_shutdown(struct snd_pcm_substream *substream, return; } + if (dai->id == BTFM_FM_SLIM_TX) + goto out; + /* Search for dai->id matched port handler */ for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) && @@ -131,6 +134,7 @@ static void btfm_slim_dai_shutdown(struct snd_pcm_substream *substream, } btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan); +out: btfm_slim_hw_deinit(btfmslim); } @@ -201,6 +205,61 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, return ret; } +static int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret = -EINVAL, i; + struct btfmslim *btfmslim = dai->dev->platform_data; + struct btfmslim_ch *ch; + uint8_t rxport, grp = false, nchan = 1; + + BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, + dai->id, dai->rate); + + switch (dai->id) { + case BTFM_FM_SLIM_TX: + grp = true; nchan = 2; + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_SLIM_TX: + ch = btfmslim->tx_chs; + rxport = 0; + break; + case BTFM_BT_SCO_A2DP_SLIM_RX: + case BTFM_BT_SPLIT_A2DP_SLIM_RX: + ch = btfmslim->rx_chs; + rxport = 1; + break; + case BTFM_SLIM_NUM_CODEC_DAIS: + default: + BTFMSLIM_ERR("dai->id is invalid:%d", dai->id); + goto out; + } + + if (dai->id != BTFM_FM_SLIM_TX) { + ret = 0; + goto out; + } + + /* Search for dai->id matched port handler */ + for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != BTFM_SLIM_NUM_CODEC_DAIS) && + (ch->id != dai->id); ch++, i++) + ; + + if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) || + (ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) { + BTFMSLIM_ERR("ch is invalid!!"); + goto out; + } + + btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan); + +out: + return ret; +} + /* This function will be called once during boot up */ static int btfm_slim_dai_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, unsigned int *tx_slot, @@ -343,6 +402,7 @@ static struct snd_soc_dai_ops btfmslim_dai_ops = { .shutdown = btfm_slim_dai_shutdown, .hw_params = btfm_slim_dai_hw_params, .prepare = btfm_slim_dai_prepare, + .hw_free = btfm_slim_dai_hw_free, .set_channel_map = btfm_slim_dai_set_channel_map, .get_channel_map = btfm_slim_dai_get_channel_map, }; diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c index 79e350c5dc320c863cc4cf0b0f9d11311066115a..0c4e0b3d5c2e747e5f536a67420896909a31a7b9 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.c +++ b/drivers/bluetooth/btfm_slim_wcn3990.c @@ -82,12 +82,11 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, uint8_t rxport, uint8_t enable) { int ret = 0; - uint8_t reg_val = 0, en; + uint8_t reg_val = 0; uint8_t port_bit = 0; uint16_t reg; BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable); - if (rxport) { if (enable) { /* For SCO Rx, A2DP Rx */ @@ -118,20 +117,7 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); if (ret) { - BTFMSLIM_ERR("failed to write (%d) reg 0x%x", - ret, reg); - goto error; - } - } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) { - /* SCO Tx */ - reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO; - reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); - BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", - reg_val, reg); - ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); - if (ret) { - BTFMSLIM_ERR("failed to write (%d) reg 0x%x", - ret, reg); + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); goto error; } } @@ -151,19 +137,15 @@ enable_disable_txport: reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num); enable_disable_rxport: - if (enable) - en = CHRK_SB_PGD_PORT_ENABLE; - else - en = CHRK_SB_PGD_PORT_DISABLE; - - if (is_fm_port(port_num)) - reg_val = en | CHRK_SB_PGD_PORT_WM_L8; - else - reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_LB : en; - - if (enable && port_num == CHRK_SB_PGD_PORT_TX_SCO) - BTFMSLIM_INFO("programming SCO Tx with reg_val %d to reg 0x%x", - reg_val, reg); + if (enable) { + if (is_fm_port(port_num)) + reg_val = CHRK_SB_PGD_PORT_ENABLE | + CHRK_SB_PGD_PORT_WM_L3; + else + reg_val = CHRK_SB_PGD_PORT_ENABLE | + CHRK_SB_PGD_PORT_WM_LB; + } else + reg_val = CHRK_SB_PGD_PORT_DISABLE; ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); if (ret) diff --git a/drivers/bluetooth/btfm_slim_wcn3990.h b/drivers/bluetooth/btfm_slim_wcn3990.h index b637ac581201d049b04aae4200a4b796a9667ee4..f6a260096c91e3deb5be205f3f68b031a8b38736 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.h +++ b/drivers/bluetooth/btfm_slim_wcn3990.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -68,7 +68,6 @@ #define CHRK_SB_PGD_PORT_WM_L1 (0x1 << 1) #define CHRK_SB_PGD_PORT_WM_L2 (0x2 << 1) #define CHRK_SB_PGD_PORT_WM_L3 (0x3 << 1) -#define CHRK_SB_PGD_PORT_WM_L8 (0x8 << 1) #define CHRK_SB_PGD_PORT_WM_LB (0xB << 1) #define CHRK_SB_PGD_PORT_RX_NUM 16 diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index cc8ee551cbacef6aa978ab6597cbae4ef5038052..13016f32b344b976431545f02811f22c4097d71e 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -58,7 +58,6 @@ #define FASTRPC_ENOSUCH 39 #define VMID_SSC_Q6 5 #define VMID_ADSP_Q6 6 -#define AC_VM_ADSP_HEAP_SHARED 33 #define DEBUGFS_SIZE 1024 #define RPC_TIMEOUT (5 * HZ) @@ -213,7 +212,6 @@ struct fastrpc_channel_ctx { struct device *dev; struct fastrpc_session_ctx session[NUM_SESSIONS]; struct completion work; - struct completion workport; struct notifier_block nb; struct kref kref; int channel; @@ -223,7 +221,6 @@ struct fastrpc_channel_ctx { int prevssrcount; int issubsystemup; int vmid; - int heap_vmid; int ramdumpenabled; void *remoteheap_ramdump_dev; struct fastrpc_glink_info link; @@ -293,7 +290,6 @@ struct fastrpc_file { int cid; int ssrcount; int pd; - int file_close; struct fastrpc_apps *apps; struct fastrpc_perf perf; struct dentry *debugfs_file; @@ -322,7 +318,6 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .channel = SMD_APPS_DSPS, .link.link_info.edge = "dsps", .link.link_info.transport = "smem", - .vmid = VMID_SSC_Q6, }, { .name = "cdsprpc-smd", @@ -703,7 +698,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned attr, if (vmid) { int srcVM[1] = {VMID_HLOS}; int destVM[2] = {VMID_HLOS, vmid}; - int destVMperm[2] = {PERM_READ | PERM_WRITE | PERM_EXEC, + int destVMperm[2] = {PERM_READ | PERM_WRITE, PERM_READ | PERM_WRITE | PERM_EXEC}; VERIFY(err, !hyp_assign_phys(map->phys, @@ -775,7 +770,7 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, ssize_t size, if (vmid) { int srcVM[1] = {VMID_HLOS}; int destVM[2] = {VMID_HLOS, vmid}; - int destVMperm[2] = {PERM_READ | PERM_WRITE | PERM_EXEC, + int destVMperm[2] = {PERM_READ | PERM_WRITE, PERM_READ | PERM_WRITE | PERM_EXEC}; VERIFY(err, !hyp_assign_phys(buf->phys, buf_page_size(size), @@ -1256,18 +1251,9 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (map && (map->attr & FASTRPC_ATTR_COHERENT)) continue; - if (rpra[i].buf.len && ctx->overps[oix]->mstart) { - if (map && map->handle) - msm_ion_do_cache_op(ctx->fl->apps->client, - map->handle, - uint64_to_ptr(rpra[i].buf.pv), - rpra[i].buf.len, - ION_IOC_CLEAN_INV_CACHES); - else - dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv), - uint64_to_ptr(rpra[i].buf.pv - + rpra[i].buf.len)); - } + if (rpra[i].buf.len && ctx->overps[oix]->mstart) + dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv), + uint64_to_ptr(rpra[i].buf.pv + rpra[i].buf.len)); } PERF_END); @@ -1278,6 +1264,11 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) rpra[inh + i].h = ctx->lpra[inh + i].h; } + if (!ctx->fl->sctx->smmu.coherent) { + PERF(ctx->fl->profile, ctx->fl->perf.flush, + dmac_flush_range((char *)rpra, (char *)rpra + ctx->used); + PERF_END); + } bail: return err; } @@ -1341,33 +1332,14 @@ static void inv_args_pre(struct smq_invoke_ctx *ctx) if (buf_page_start(ptr_to_uint64((void *)rpra)) == buf_page_start(rpra[i].buf.pv)) continue; - if (!IS_CACHE_ALIGNED((uintptr_t) - uint64_to_ptr(rpra[i].buf.pv))) { - if (map && map->handle) - msm_ion_do_cache_op(ctx->fl->apps->client, - map->handle, - uint64_to_ptr(rpra[i].buf.pv), - sizeof(uintptr_t), - ION_IOC_CLEAN_INV_CACHES); - else - dmac_flush_range( - uint64_to_ptr(rpra[i].buf.pv), (char *) - uint64_to_ptr(rpra[i].buf.pv + 1)); - } - + if (!IS_CACHE_ALIGNED((uintptr_t)uint64_to_ptr(rpra[i].buf.pv))) + dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv), + (char *)(uint64_to_ptr(rpra[i].buf.pv + 1))); end = (uintptr_t)uint64_to_ptr(rpra[i].buf.pv + rpra[i].buf.len); - if (!IS_CACHE_ALIGNED(end)) { - if (map && map->handle) - msm_ion_do_cache_op(ctx->fl->apps->client, - map->handle, - uint64_to_ptr(end), - sizeof(uintptr_t), - ION_IOC_CLEAN_INV_CACHES); - else - dmac_flush_range((char *)end, - (char *)end + 1); - } + if (!IS_CACHE_ALIGNED(end)) + dmac_flush_range((char *)end, + (char *)end + 1); } } @@ -1376,6 +1348,7 @@ static void inv_args(struct smq_invoke_ctx *ctx) int i, inbufs, outbufs; uint32_t sc = ctx->sc; remote_arg64_t *rpra = ctx->rpra; + int used = ctx->used; int inv = 0; inbufs = REMOTE_SCALARS_INBUFS(sc); @@ -1408,6 +1381,8 @@ static void inv_args(struct smq_invoke_ctx *ctx) + rpra[i].buf.len)); } + if (inv || REMOTE_SCALARS_OUTHANDLES(sc)) + dmac_inv_range(rpra, (char *)rpra + used); } static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx, @@ -1478,7 +1453,7 @@ static void smd_event_handler(void *priv, unsigned event) switch (event) { case SMD_EVENT_OPEN: - complete(&me->channel[cid].workport); + complete(&me->channel[cid].work); break; case SMD_EVENT_CLOSE: fastrpc_notify_drivers(me, cid); @@ -1499,7 +1474,6 @@ static void fastrpc_init(struct fastrpc_apps *me) me->channel = &gcinfo[0]; for (i = 0; i < NUM_CHANNELS; i++) { init_completion(&me->channel[i].work); - init_completion(&me->channel[i].workport); me->channel[i].sesscount = 0; } } @@ -1616,7 +1590,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, struct fastrpc_mmap *file = 0, *mem = 0; char *proc_name = NULL; int srcVM[1] = {VMID_HLOS}; - int destVM[1] = {gcinfo[0].heap_vmid}; + int destVM[1] = {VMID_ADSP_Q6}; int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; int hlosVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; @@ -1875,7 +1849,7 @@ static int fastrpc_mmap_on_dsp(struct fastrpc_file *fl, uint32_t flags, } else if (flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { int srcVM[1] = {VMID_HLOS}; - int destVM[1] = {gcinfo[0].heap_vmid}; + int destVM[1] = {VMID_ADSP_Q6}; int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; VERIFY(err, !hyp_assign_phys(map->phys, (uint64_t)map->size, @@ -1891,7 +1865,7 @@ static int fastrpc_munmap_on_dsp_rh(struct fastrpc_file *fl, struct fastrpc_mmap *map) { int err = 0; - int srcVM[1] = {gcinfo[0].heap_vmid}; + int srcVM[1] = {VMID_ADSP_Q6}; int destVM[1] = {VMID_HLOS}; int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; @@ -2161,7 +2135,7 @@ void fastrpc_glink_notify_state(void *handle, const void *priv, unsigned event) switch (event) { case GLINK_CONNECTED: link->port_state = FASTRPC_LINK_CONNECTED; - complete(&me->channel[cid].workport); + complete(&me->channel[cid].work); break; case GLINK_LOCAL_DISCONNECTED: link->port_state = FASTRPC_LINK_DISCONNECTED; @@ -2219,9 +2193,6 @@ static int fastrpc_file_free(struct fastrpc_file *fl) return 0; } (void)fastrpc_release_current_dsp_process(fl); - spin_lock(&fl->hlock); - fl->file_close = 1; - spin_unlock(&fl->hlock); fastrpc_context_list_dtor(fl); fastrpc_buf_list_free(fl); hlist_for_each_entry_safe(map, n, &fl->maps, hn) { @@ -2314,7 +2285,8 @@ static void fastrpc_glink_close(void *chan, int cid) return; link = &gfa.channel[cid].link; - if (link->port_state == FASTRPC_LINK_CONNECTED) { + if (link->port_state == FASTRPC_LINK_CONNECTED || + link->port_state == FASTRPC_LINK_CONNECTING) { link->port_state = FASTRPC_LINK_DISCONNECTING; glink_close(chan); } @@ -2422,16 +2394,16 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, spin_lock(&fl->hlock); hlist_for_each_entry_safe(buf, n, &fl->bufs, hn) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, - "%s %pK %s %pK %s %llx\n", "buf:", - buf, "buf->virt:", buf->virt, - "buf->phys:", buf->phys); + "%s %p %s %p %s %llx\n", "buf:", + buf, "buf->virt:", buf->virt, + "buf->phys:", buf->phys); } len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "\n%s\n", "LIST OF MAPS:"); hlist_for_each_entry_safe(map, n, &fl->maps, hn) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, - "%s %pK %s %lx %s %llx\n", + "%s %p %s %lx %s %llx\n", "map:", map, "map->va:", map->va, "map->phys:", map->phys); @@ -2441,7 +2413,7 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, "LIST OF PENDING SMQCONTEXTS:"); hlist_for_each_entry_safe(ictx, n, &fl->clst.pending, hn) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, - "%s %pK %s %u %s %u %s %u\n", + "%s %p %s %u %s %u %s %u\n", "smqcontext:", ictx, "sc:", ictx->sc, "tid:", ictx->pid, @@ -2452,7 +2424,7 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, "LIST OF INTERRUPTED SMQCONTEXTS:"); hlist_for_each_entry_safe(ictx, n, &fl->clst.interrupted, hn) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, - "%s %pK %s %u %s %u %s %u\n", + "%s %p %s %u %s %u %s %u\n", "smqcontext:", ictx, "sc:", ictx->sc, "tid:", ictx->pid, @@ -2512,9 +2484,8 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) if (err) goto bail; - VERIFY(err, - wait_for_completion_timeout(&me->channel[cid].workport, - RPC_TIMEOUT)); + VERIFY(err, wait_for_completion_timeout(&me->channel[cid].work, + RPC_TIMEOUT)); if (err) { me->channel[cid].chan = 0; goto bail; @@ -2522,9 +2493,6 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) kref_init(&me->channel[cid].kref); pr_info("'opened /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); - err = glink_queue_rx_intent(me->channel[cid].chan, NULL, 64); - if (err) - pr_info("adsprpc: initial intent failed for %d\n", cid); if (cid == 0 && me->channel[cid].ssrcount != me->channel[cid].prevssrcount) { if (fastrpc_mmap_remove_ssr(fl)) @@ -2613,14 +2581,6 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, p.inv.fds = 0; p.inv.attrs = 0; - spin_lock(&fl->hlock); - if (fl->file_close == 1) { - err = EBADF; - pr_warn("ADSPRPC: fastrpc_device_release is happening, So not sending any new requests to DSP"); - spin_unlock(&fl->hlock); - goto bail; - } - spin_unlock(&fl->hlock); switch (ioctl_num) { case FASTRPC_IOCTL_INVOKE: @@ -2718,10 +2678,6 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, if (!size) size = sizeof(struct fastrpc_ioctl_init_attrs); VERIFY(err, 0 == copy_from_user(&p.init, param, size)); - if (err) - goto bail; - VERIFY(err, p.init.init.filelen >= 0 && - p.init.init.memlen >= 0); if (err) goto bail; VERIFY(err, 0 == fastrpc_init_process(fl, &p.init)); @@ -2869,7 +2825,6 @@ static int fastrpc_cb_probe(struct device *dev) chan->sesscount++; debugfs_global_file = debugfs_create_file("global", 0644, debugfs_root, NULL, &debugfs_fops); - bail: return err; } @@ -2983,12 +2938,6 @@ static int fastrpc_probe(struct platform_device *pdev) } return 0; } - if (of_property_read_bool(dev->of_node, - "qcom,fastrpc-vmid-heap-shared")) - gcinfo[0].heap_vmid = AC_VM_ADSP_HEAP_SHARED; - else - gcinfo[0].heap_vmid = VMID_ADSP_Q6; - pr_info("ADSPRPC: gcinfo[0].heap_vmid %d\n", gcinfo[0].heap_vmid); me->glink = of_property_read_bool(dev->of_node, "qcom,fastrpc-glink"); VERIFY(err, !of_platform_populate(pdev->dev.of_node, fastrpc_match_table, diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 4eb1c772ded702406850d93488f0b293c96ac317..334e14c9cd07944c445b264ff3d738d278558ad8 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -25,6 +25,11 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _AGP_BACKEND_PRIV_H #define _AGP_BACKEND_PRIV_H 1 diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index f002fa5d1887a0b183b2532891fd853c2587f239..eccf3fed9378f1fcda175b08e6570e6cbefbb6b3 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -27,6 +27,11 @@ * TODO: * - Allocate more than order 0 pages to avoid too much linear map splitting. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index e206d9db4d7de2d774de5a603b94159fa01fd2c7..20e617ed0770cf5be9d4bb153c98f8c2b762833b 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -320,7 +320,6 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; struct diag_ctrl_msg_mask header; - uint8_t msg_mask_tbl_count_local; if (peripheral >= NUM_PERIPHERALS) return; @@ -361,8 +360,6 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) return; } buf = mask_info->update_buf; - msg_mask_tbl_count_local = driver->msg_mask_tbl_count; - mutex_unlock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); switch (mask_info->status) { case DIAG_CTRL_MASK_ALL_DISABLED: @@ -379,11 +376,9 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) goto err; } - for (i = 0; i < msg_mask_tbl_count_local; i++, mask++) { - mutex_lock(&driver->msg_mask_lock); - if (((mask->ssid_first > first) || - (mask->ssid_last_tools < last)) && first != ALL_SSID) { - mutex_unlock(&driver->msg_mask_lock); + for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + if (((first < mask->ssid_first) || + (last > mask->ssid_last_tools)) && first != ALL_SSID) { continue; } @@ -424,19 +419,19 @@ proceed: if (mask_size > 0) memcpy(buf + header_len, mask->ptr, mask_size); mutex_unlock(&mask->lock); - mutex_unlock(&driver->msg_mask_lock); err = diagfwd_write(peripheral, TYPE_CNTL, buf, header_len + mask_size); if (err && err != -ENODEV) - pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d, error = %d\n", - peripheral, err); + pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d\n", + peripheral); if (first != ALL_SSID) break; } err: mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->msg_mask_lock); } static void diag_send_time_sync_update(uint8_t peripheral) @@ -716,8 +711,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, } req = (struct diag_msg_build_mask_t *)src_buf; - mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); + mutex_lock(&mask_info->lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { if (i < (driver->msg_mask_tbl_count - 1)) { @@ -757,8 +752,6 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, pr_err_ratelimited("diag: In %s, unable to allocate memory for msg mask ptr, mask_size: %d\n", __func__, mask_size); mutex_unlock(&mask->lock); - mutex_unlock(&driver->msg_mask_lock); - mutex_unlock(&mask_info->lock); return -ENOMEM; } mask->ptr = temp; @@ -777,8 +770,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mask_info->status = DIAG_CTRL_MASK_VALID; break; } - mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->msg_mask_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(MSG_MASKS_TYPE); @@ -803,9 +796,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_PERIPHERALS; i++) { if (!diag_check_update(i)) continue; - mutex_lock(&driver->md_session_lock); diag_send_msg_mask_update(i, req->ssid_first, req->ssid_last); - mutex_unlock(&driver->md_session_lock); } end: return write_len; @@ -833,11 +824,9 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, } req = (struct diag_msg_config_rsp_t *)src_buf; - - mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); - mask = (struct diag_msg_mask_t *)mask_info->ptr; + mutex_lock(&mask_info->lock); mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED : DIAG_CTRL_MASK_ALL_DISABLED; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { @@ -846,8 +835,8 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mask->range * sizeof(uint32_t)); mutex_unlock(&mask->lock); } - mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->msg_mask_lock); if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(MSG_MASKS_TYPE); @@ -867,9 +856,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_PERIPHERALS; i++) { if (!diag_check_update(i)) continue; - mutex_lock(&driver->md_session_lock); diag_send_msg_mask_update(i, ALL_SSID, ALL_SSID); - mutex_unlock(&driver->md_session_lock); } return write_len; @@ -963,9 +950,7 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_PERIPHERALS; i++) { if (!diag_check_update(i)) continue; - mutex_lock(&driver->md_session_lock); diag_send_event_mask_update(i); - mutex_unlock(&driver->md_session_lock); } return write_len; @@ -1012,9 +997,7 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_PERIPHERALS; i++) { if (!diag_check_update(i)) continue; - mutex_lock(&driver->md_session_lock); diag_send_event_mask_update(i); - mutex_unlock(&driver->md_session_lock); } memcpy(dest_buf, &header, sizeof(header)); write_len += sizeof(header); @@ -1268,9 +1251,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_PERIPHERALS; i++) { if (!diag_check_update(i)) continue; - mutex_lock(&driver->md_session_lock); diag_send_log_mask_update(i, req->equip_id); - mutex_unlock(&driver->md_session_lock); } end: return write_len; @@ -1321,9 +1302,7 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_PERIPHERALS; i++) { if (!diag_check_update(i)) continue; - mutex_lock(&driver->md_session_lock); diag_send_log_mask_update(i, ALL_EQUIP_ID); - mutex_unlock(&driver->md_session_lock); } return write_len; @@ -1361,8 +1340,8 @@ static int diag_create_msg_mask_table(void) struct diag_msg_mask_t *mask = (struct diag_msg_mask_t *)msg_mask.ptr; struct diag_ssid_range_t range; - mutex_lock(&msg_mask.lock); mutex_lock(&driver->msg_mask_lock); + mutex_lock(&msg_mask.lock); driver->msg_mask_tbl_count = MSG_MASK_TBL_CNT; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; @@ -1371,8 +1350,8 @@ static int diag_create_msg_mask_table(void) if (err) break; } - mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&msg_mask.lock); + mutex_unlock(&driver->msg_mask_lock); return err; } @@ -1385,8 +1364,8 @@ static int diag_create_build_time_mask(void) struct diag_msg_mask_t *build_mask = NULL; struct diag_ssid_range_t range; - mutex_lock(&msg_bt_mask.lock); mutex_lock(&driver->msg_mask_lock); + mutex_lock(&msg_bt_mask.lock); driver->bt_msg_mask_tbl_count = MSG_MASK_TBL_CNT; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { @@ -1499,8 +1478,9 @@ static int diag_create_build_time_mask(void) } memcpy(build_mask->ptr, tbl, tbl_size); } - mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&msg_bt_mask.lock); + mutex_unlock(&driver->msg_mask_lock); + return err; } @@ -1670,8 +1650,8 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) err = __diag_mask_init(dest, MSG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; - mutex_lock(&dest->lock); mutex_lock(&driver->msg_mask_lock); + mutex_lock(&dest->lock); src_mask = (struct diag_msg_mask_t *)src->ptr; dest_mask = (struct diag_msg_mask_t *)dest->ptr; @@ -1688,8 +1668,9 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) src_mask++; dest_mask++; } - mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&dest->lock); + mutex_unlock(&driver->msg_mask_lock); + return err; } @@ -1700,15 +1681,15 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) if (!mask_info) return; - mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); + mutex_lock(&mask_info->lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; } - mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->msg_mask_lock); __diag_mask_exit(mask_info); } @@ -1877,9 +1858,8 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, return -EIO; } mutex_unlock(&driver->diag_maskclear_mutex); - mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); - + mutex_lock(&mask_info->lock); mask = (struct diag_msg_mask_t *)(mask_info->ptr); for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { ptr = mask_info->update_buf; @@ -1916,8 +1896,8 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, } total_len += len; } - mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); + mutex_unlock(&driver->msg_mask_lock); return err ? err : total_len; } @@ -1986,11 +1966,9 @@ void diag_send_updates_peripheral(uint8_t peripheral) diag_send_feature_mask_update(peripheral); if (driver->time_sync_enabled) diag_send_time_sync_update(peripheral); - mutex_lock(&driver->md_session_lock); diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID); diag_send_log_mask_update(peripheral, ALL_EQUIP_ID); diag_send_event_mask_update(peripheral); - mutex_unlock(&driver->md_session_lock); diag_send_real_time_update(peripheral, driver->real_time_mode[DIAG_LOCAL_PROC]); diag_send_peripheral_buffering_mode( diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index a27f12883c8dc966279221f1f98feeec8e7ff47f..06b83f5230bf993390911cb5a65c530528111149 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -129,6 +129,37 @@ void diag_md_close_all() diag_ws_reset(DIAG_WS_MUX); } +static int diag_md_get_peripheral(int ctxt) +{ + int peripheral; + + if (driver->num_pd_session) { + peripheral = GET_PD_CTXT(ctxt); + switch (peripheral) { + case UPD_WLAN: + case UPD_AUDIO: + case UPD_SENSORS: + break; + case DIAG_ID_MPSS: + case DIAG_ID_LPASS: + case DIAG_ID_CDSP: + default: + peripheral = + GET_BUF_PERIPHERAL(ctxt); + if (peripheral > NUM_PERIPHERALS) + peripheral = -EINVAL; + break; + } + } else { + /* Account for Apps data as well */ + peripheral = GET_BUF_PERIPHERAL(ctxt); + if (peripheral > NUM_PERIPHERALS) + peripheral = -EINVAL; + } + + return peripheral; +} + int diag_md_write(int id, unsigned char *buf, int len, int ctx) { int i; diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c index 8cc803eef55217f89515e9f251af3aa5cd855635..d6f6ea7af8ea5f3afe3753e007dc7fa71d117544 100644 --- a/drivers/char/diag/diag_mux.c +++ b/drivers/char/diag/diag_mux.c @@ -153,15 +153,12 @@ int diag_mux_write(int proc, unsigned char *buf, int len, int ctx) upd = PERIPHERAL_CDSP; break; case UPD_WLAN: - if (!driver->pd_logging_mode[0]) + if (!driver->num_pd_session) upd = PERIPHERAL_MODEM; break; case UPD_AUDIO: - if (!driver->pd_logging_mode[1]) - upd = PERIPHERAL_LPASS; - break; case UPD_SENSORS: - if (!driver->pd_logging_mode[2]) + if (!driver->num_pd_session) upd = PERIPHERAL_LPASS; break; default: diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index d81a39e2c6376431626d8bb73095b46232bb8d01..cc56d68217b3c376594fa3f3d40260daf6681b72 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -642,7 +642,6 @@ struct diagchar_dev { #endif int time_sync_enabled; uint8_t uses_time_api; - struct platform_device *pdev; }; extern struct diagchar_dev *driver; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 4111e599877a152d654421329d32442e1557efe9..5ae3e4defd0de35ebf3a2a143aacdf8e64ff917e 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -22,8 +22,6 @@ #include #include #include -#include -#include #ifdef CONFIG_DIAG_OVER_USB #include #endif @@ -458,7 +456,6 @@ static void diag_close_logging_process(const int pid) { int i, j; int session_mask; - uint32_t p_mask; struct diag_md_session_t *session_info = NULL; struct diag_logging_mode_param_t params; @@ -478,9 +475,6 @@ static void diag_close_logging_process(const int pid) session_mask = session_info->peripheral_mask; diag_md_session_close(session_info); - p_mask = - diag_translate_kernel_to_user_mask(session_mask); - for (i = 0; i < NUM_MD_SESSIONS; i++) if (MD_PERIPHERAL_MASK(i) & session_mask) diag_mux_close_peripheral(DIAG_LOCAL_PROC, i); @@ -488,17 +482,19 @@ static void diag_close_logging_process(const int pid) params.req_mode = USB_MODE; params.mode_param = 0; params.pd_mask = 0; - params.peripheral_mask = p_mask; + params.peripheral_mask = + diag_translate_kernel_to_user_mask(session_mask); if (driver->num_pd_session > 0) { - for (i = UPD_WLAN; (i < NUM_MD_SESSIONS); i++) { - if (session_mask & MD_PERIPHERAL_MASK(i)) { - j = i - UPD_WLAN; - driver->pd_session_clear[j] = 1; - driver->pd_logging_mode[j] = 0; - driver->num_pd_session -= 1; - params.pd_mask = p_mask; - } + for (i = UPD_WLAN; ((i < NUM_MD_SESSIONS) && + (session_mask & MD_PERIPHERAL_MASK(i))); + i++) { + j = i - UPD_WLAN; + driver->pd_session_clear[j] = 1; + driver->pd_logging_mode[j] = 0; + driver->num_pd_session -= 1; + params.pd_mask = + diag_translate_kernel_to_user_mask(session_mask); } } @@ -703,11 +699,6 @@ static void diag_cmd_invalidate_polling(int change_flag) driver->polling_reg_flag = 0; list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); - if (&item->entry == NULL) { - pr_err("diag: In %s, unable to search command\n", - __func__); - return; - } polling = diag_cmd_chk_polling(&item->entry); if (polling == DIAG_CMD_POLLING) { driver->polling_reg_flag = 1; @@ -849,12 +840,6 @@ void diag_cmd_remove_reg_by_pid(int pid) mutex_lock(&driver->cmd_reg_mutex); list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); - if (&item->entry == NULL) { - pr_err("diag: In %s, unable to search command\n", - __func__); - mutex_unlock(&driver->cmd_reg_mutex); - return; - } if (item->pid == pid) { list_del(&item->link); kfree(item); @@ -873,12 +858,6 @@ void diag_cmd_remove_reg_by_proc(int proc) mutex_lock(&driver->cmd_reg_mutex); list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); - if (&item->entry == NULL) { - pr_err("diag: In %s, unable to search command\n", - __func__); - mutex_unlock(&driver->cmd_reg_mutex); - return; - } if (item->proc == proc) { list_del(&item->link); kfree(item); @@ -1855,18 +1834,14 @@ static int diag_ioctl_lsm_deinit(void) { int i; - mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; - if (i == driver->num_clients) { - mutex_unlock(&driver->diagchar_mutex); + if (i == driver->num_clients) return -EINVAL; - } driver->data_ready[i] |= DEINIT_TYPE; - mutex_unlock(&driver->diagchar_mutex); wake_up_interruptible(&driver->wait_q); return 1; @@ -3029,16 +3004,6 @@ static int diag_user_process_apps_data(const char __user *buf, int len, return 0; } -static int check_data_ready(int index) -{ - int data_type = 0; - - mutex_lock(&driver->diagchar_mutex); - data_type = driver->data_ready[index]; - mutex_unlock(&driver->diagchar_mutex); - return data_type; -} - static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -3051,11 +3016,9 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, int write_len = 0; struct diag_md_session_t *session_info = NULL; - mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) index = i; - mutex_unlock(&driver->diagchar_mutex); if (index == -1) { pr_err("diag: Client PID not found in table"); @@ -3065,7 +3028,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, pr_err("diag: bad address from user side\n"); return -EFAULT; } - wait_event_interruptible(driver->wait_q, (check_data_ready(index)) > 0); + wait_event_interruptible(driver->wait_q, driver->data_ready[index]); mutex_lock(&driver->diagchar_mutex); @@ -3206,11 +3169,11 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, } exit: + mutex_unlock(&driver->diagchar_mutex); if (driver->data_ready[index] & DCI_DATA_TYPE) { - data_type = driver->data_ready[index] & DCI_DATA_TYPE; - mutex_unlock(&driver->diagchar_mutex); - /* Copy the type of data being passed */ mutex_lock(&driver->dci_mutex); + /* Copy the type of data being passed */ + data_type = driver->data_ready[index] & DCI_DATA_TYPE; list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); @@ -3242,7 +3205,6 @@ exit: mutex_unlock(&driver->dci_mutex); goto end; } - mutex_unlock(&driver->diagchar_mutex); end: /* * Flush any read that is currently pending on DCI data and @@ -3621,41 +3583,6 @@ static int diagchar_cleanup(void) return 0; } -static int diag_mhi_probe(struct platform_device *pdev) -{ - int ret; - - if (!mhi_is_device_ready(&pdev->dev, "qcom,mhi")) - return -EPROBE_DEFER; - driver->pdev = pdev; - ret = diag_remote_init(); - if (ret) { - diag_remote_exit(); - return ret; - } - ret = diagfwd_bridge_init(); - if (ret) { - diagfwd_bridge_exit(); - return ret; - } - pr_debug("diag: mhi device is ready\n"); - return 0; -} - -static const struct of_device_id diag_mhi_table[] = { - {.compatible = "qcom,diag-mhi"}, - {}, -}; - -static struct platform_driver diag_mhi_driver = { - .probe = diag_mhi_probe, - .driver = { - .name = "DIAG MHI Platform", - .owner = THIS_MODULE, - .of_match_table = diag_mhi_table, - }, -}; - static int __init diagchar_init(void) { dev_t dev; @@ -3743,6 +3670,9 @@ static int __init diagchar_init(void) if (ret) goto fail; ret = diag_masks_init(); + if (ret) + goto fail; + ret = diag_remote_init(); if (ret) goto fail; ret = diag_mux_init(); @@ -3781,7 +3711,9 @@ static int __init diagchar_init(void) goto fail; pr_debug("diagchar initialized now"); - platform_driver_register(&diag_mhi_driver); + ret = diagfwd_bridge_init(); + if (ret) + diagfwd_bridge_exit(); return 0; fail: @@ -3795,7 +3727,9 @@ fail: diagfwd_cntl_exit(); diag_dci_exit(); diag_masks_exit(); + diag_remote_exit(); return -1; + } static void diagchar_exit(void) diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h index 97ad3f60ba5ec9b96929603c356cd5686e064b01..577377b32cdaabbd5d48719a186f27714c0a30b7 100644 --- a/drivers/char/diag/diagfwd.h +++ b/drivers/char/diag/diagfwd.h @@ -26,7 +26,7 @@ #define GET_PD_CTXT(u) ((u & 0xFF000000) >> 24) #define CHK_OVERFLOW(bufStart, start, end, length) \ - ((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0) +((((bufStart) <= (start)) && (end - start >= (length)) && (length > 0)) ? 1 : 0) int diagfwd_init(void); void diagfwd_exit(void); diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index 10038e629e6c54bbeb6d6b0b8bc8208f535e181a..4ae2158b5a6b267a907b65a524c37530f82baed8 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -67,6 +67,7 @@ void diag_cntl_channel_close(struct diagfwd_info *p_info) driver->feature[peripheral].sent_feature_mask = 0; driver->feature[peripheral].rcvd_feature_mask = 0; + flush_workqueue(driver->cntl_wq); reg_dirty |= PERIPHERAL_MASK(peripheral); diag_cmd_remove_reg_by_proc(peripheral); driver->feature[peripheral].stm_support = DISABLE_STM; @@ -1119,18 +1120,6 @@ void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral) *diag_id = DIAG_ID_LPASS; *peripheral = PERIPHERAL_LPASS; break; - case PERIPHERAL_WCNSS: - *diag_id = 0; - *peripheral = PERIPHERAL_WCNSS; - break; - case PERIPHERAL_SENSORS: - *diag_id = 0; - *peripheral = PERIPHERAL_SENSORS; - break; - case PERIPHERAL_WDSP: - *diag_id = 0; - *peripheral = PERIPHERAL_WDSP; - break; case PERIPHERAL_CDSP: *diag_id = DIAG_ID_CDSP; *peripheral = PERIPHERAL_CDSP; diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c index f1f8f0b2b34bcca45509297c9e88c9f9a84dcefc..03d496c2dd91764e5d4439660223ad9a37916087 100644 --- a/drivers/char/diag/diagfwd_glink.c +++ b/drivers/char/diag/diagfwd_glink.c @@ -361,44 +361,13 @@ static void diag_glink_read_work_fn(struct work_struct *work) diagfwd_channel_read(glink_info->fwd_ctxt); } -struct diag_glink_read_work { - struct diag_glink_info *glink_info; - const void *ptr_read_done; - const void *ptr_rx_done; - size_t ptr_read_size; - struct work_struct work; -}; - -static void diag_glink_notify_rx_work_fn(struct work_struct *work) -{ - struct diag_glink_read_work *read_work = container_of(work, - struct diag_glink_read_work, work); - struct diag_glink_info *glink_info = read_work->glink_info; - - if (!glink_info || !glink_info->hdl) { - kfree(read_work); - return; - } - - diagfwd_channel_read_done(glink_info->fwd_ctxt, - (unsigned char *)(read_work->ptr_read_done), - read_work->ptr_read_size); - - glink_rx_done(glink_info->hdl, read_work->ptr_rx_done, false); - - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: Rx done for packet %pK of len: %d periph: %d ch: %d\n", - read_work->ptr_rx_done, (int)read_work->ptr_read_size, - glink_info->peripheral, glink_info->type); - kfree(read_work); -} static void diag_glink_notify_rx(void *hdl, const void *priv, const void *pkt_priv, const void *ptr, size_t size) { struct diag_glink_info *glink_info = (struct diag_glink_info *)priv; - struct diag_glink_read_work *read_work; + int err = 0; if (!glink_info || !glink_info->hdl || !ptr || !pkt_priv || !hdl) return; @@ -410,25 +379,12 @@ static void diag_glink_notify_rx(void *hdl, const void *priv, "diag: received a packet %pK of len:%d from periph:%d ch:%d\n", ptr, (int)size, glink_info->peripheral, glink_info->type); - read_work = kmalloc(sizeof(*read_work), GFP_ATOMIC); - if (!read_work) { - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: Could not allocate read_work\n"); - glink_rx_done(glink_info->hdl, ptr, true); - return; - } - memcpy((void *)pkt_priv, ptr, size); - - read_work->glink_info = glink_info; - read_work->ptr_read_done = pkt_priv; - read_work->ptr_rx_done = ptr; - read_work->ptr_read_size = size; - INIT_WORK(&read_work->work, diag_glink_notify_rx_work_fn); - queue_work(glink_info->wq, &read_work->work); - + err = diagfwd_channel_read_done(glink_info->fwd_ctxt, + (unsigned char *)pkt_priv, size); + glink_rx_done(glink_info->hdl, ptr, false); DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: Rx queued for packet %pK of len: %d periph: %d ch: %d\n", + "diag: Rx done for packet %pK of len:%d periph:%d ch:%d\n", ptr, (int)size, glink_info->peripheral, glink_info->type); } @@ -517,8 +473,6 @@ static void diag_glink_connect_work_fn(struct work_struct *work) atomic_set(&glink_info->opened, 1); diagfwd_channel_open(glink_info->fwd_ctxt); diagfwd_late_open(glink_info->fwd_ctxt); - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "glink channel open: p: %d t: %d\n", - glink_info->peripheral, glink_info->type); } static void diag_glink_remote_disconnect_work_fn(struct work_struct *work) @@ -540,9 +494,9 @@ static void diag_glink_late_init_work_fn(struct work_struct *work) late_init_work); if (!glink_info || !glink_info->hdl) return; - diagfwd_channel_open(glink_info->fwd_ctxt); - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "glink late init p: %d t: %d\n", + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d\n", glink_info->peripheral, glink_info->type); + diagfwd_channel_open(glink_info->fwd_ctxt); } static void diag_glink_transport_notify_state(void *handle, const void *priv, diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index edfba6bb09c93e666e08cd467cf045a2ac39e67d..03133a5a89aa36b8d783b0ce93d792feb1864660 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -197,7 +197,7 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) struct diag_mhi_buf_tbl_t *item = NULL; struct diag_mhi_ch_t *ch = NULL; - if (!mhi_info) + if (!mhi_info || !mhi_info->enabled) return; /* Clear all the pending reads */ @@ -678,25 +678,7 @@ static int diag_mhi_register_ch(int id, struct diag_mhi_ch_t *ch) atomic_set(&(ch->opened), 0); ctxt = SET_CH_CTXT(id, ch->type); ch->client_info.mhi_client_cb = mhi_notifier; - ch->client_info.chan = ch->chan; - ch->client_info.dev = &driver->pdev->dev; - ch->client_info.node_name = "qcom,mhi"; - ch->client_info.user_data = (void *)(uintptr_t)ctxt; - return mhi_register_channel(&ch->hdl, &ch->client_info); -} - -static void diag_mhi_dev_exit(int dev) -{ - struct diag_mhi_info *mhi_info = NULL; - - mhi_info = &diag_mhi[dev]; - if (!mhi_info) - return; - if (mhi_info->mhi_wq) - destroy_workqueue(mhi_info->mhi_wq); - mhi_close(mhi_info->id); - if (mhi_info->mempool_init) - diagmem_exit(driver, mhi_info->mempool); + return mhi_register_channel(&ch->hdl, NULL); } int diag_mhi_init() @@ -744,16 +726,22 @@ int diag_mhi_init() return 0; fail: - diag_mhi_dev_exit(i); + diag_mhi_exit(); return -ENOMEM; } void diag_mhi_exit() { int i; + struct diag_mhi_info *mhi_info = NULL; for (i = 0; i < NUM_MHI_DEV; i++) { - diag_mhi_dev_exit(i); + mhi_info = &diag_mhi[i]; + if (mhi_info->mhi_wq) + destroy_workqueue(mhi_info->mhi_wq); + mhi_close(mhi_info->id); + if (mhi_info->mempool_init) + diagmem_exit(driver, mhi_info->mempool); } } diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 0f94bab3bf84d84342220b222a7ad567db1a7cd6..e209039bed5a0c6d71482119fa78f9f464c60622 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -216,45 +216,6 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) return buf->len; } -int diag_md_get_peripheral(int ctxt) -{ - int peripheral; - - if (driver->num_pd_session) { - peripheral = GET_PD_CTXT(ctxt); - switch (peripheral) { - case UPD_WLAN: - if (!driver->pd_logging_mode[0]) - peripheral = PERIPHERAL_MODEM; - break; - case UPD_AUDIO: - if (!driver->pd_logging_mode[1]) - peripheral = PERIPHERAL_LPASS; - break; - case UPD_SENSORS: - if (!driver->pd_logging_mode[2]) - peripheral = PERIPHERAL_LPASS; - break; - case DIAG_ID_MPSS: - case DIAG_ID_LPASS: - case DIAG_ID_CDSP: - default: - peripheral = - GET_BUF_PERIPHERAL(ctxt); - if (peripheral > NUM_PERIPHERALS) - peripheral = -EINVAL; - break; - } - } else { - /* Account for Apps data as well */ - peripheral = GET_BUF_PERIPHERAL(ctxt); - if (peripheral > NUM_PERIPHERALS) - peripheral = -EINVAL; - } - - return peripheral; -} - static void diagfwd_data_process_done(struct diagfwd_info *fwd_info, struct diagfwd_buf_t *buf, int len) { @@ -284,15 +245,13 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info, mutex_lock(&driver->hdlc_disable_mutex); mutex_lock(&fwd_info->data_mutex); - peripheral = diag_md_get_peripheral(buf->ctxt); - if (peripheral < 0) { - pr_err("diag:%s:%d invalid peripheral = %d\n", - __func__, __LINE__, peripheral); - mutex_unlock(&fwd_info->data_mutex); - mutex_unlock(&driver->hdlc_disable_mutex); - diag_ws_release(); - return; - } + peripheral = GET_PD_CTXT(buf->ctxt); + if (peripheral == DIAG_ID_MPSS) + peripheral = PERIPHERAL_MODEM; + if (peripheral == DIAG_ID_LPASS) + peripheral = PERIPHERAL_LPASS; + if (peripheral == DIAG_ID_CDSP) + peripheral = PERIPHERAL_CDSP; session_info = diag_md_session_get_peripheral(peripheral); @@ -500,29 +459,15 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, temp_buf_main += (buf_len + 4); processed += buf_len; } - - if (flag_buf_1) { - fwd_info->cpd_len_1 = len_cpd; - if (fwd_info->type == TYPE_DATA) - fwd_info->upd_len_1_a = len_upd_1; - if (peripheral == PERIPHERAL_LPASS && - fwd_info->type == TYPE_DATA) - fwd_info->upd_len_2_a = len_upd_2; - } else if (flag_buf_2) { - fwd_info->cpd_len_2 = len_cpd; - if (fwd_info->type == TYPE_DATA) - fwd_info->upd_len_1_b = len_upd_1; - if (peripheral == PERIPHERAL_LPASS && - fwd_info->type == TYPE_DATA) - fwd_info->upd_len_2_b = len_upd_2; - } - if (peripheral == PERIPHERAL_LPASS && fwd_info->type == TYPE_DATA && len_upd_2) { - if (flag_buf_1) + if (flag_buf_1) { + fwd_info->upd_len_2_a = len_upd_2; temp_ptr_upd = fwd_info->buf_upd_2_a; - else + } else { + fwd_info->upd_len_2_b = len_upd_2; temp_ptr_upd = fwd_info->buf_upd_2_b; + } temp_ptr_upd->ctxt &= 0x00FFFFFF; temp_ptr_upd->ctxt |= (SET_PD_CTXT(ctxt_upd_2)); @@ -536,10 +481,15 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, fwd_info->upd_len_2_b = 0; } if (fwd_info->type == TYPE_DATA && len_upd_1) { - if (flag_buf_1) + if (flag_buf_1) { + fwd_info->upd_len_1_a = + len_upd_1; temp_ptr_upd = fwd_info->buf_upd_1_a; - else + } else { + fwd_info->upd_len_1_b = + len_upd_1; temp_ptr_upd = fwd_info->buf_upd_1_b; + } temp_ptr_upd->ctxt &= 0x00FFFFFF; temp_ptr_upd->ctxt |= (SET_PD_CTXT(ctxt_upd_1)); @@ -553,6 +503,10 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, fwd_info->upd_len_1_b = 0; } if (len_cpd) { + if (flag_buf_1) + fwd_info->cpd_len_1 = len_cpd; + else + fwd_info->cpd_len_2 = len_cpd; temp_ptr_cpd->ctxt &= 0x00FFFFFF; temp_ptr_cpd->ctxt |= (SET_PD_CTXT(ctxt_cpd)); @@ -1245,14 +1199,7 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info) mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 1; diagfwd_buffers_init(fwd_info); - - /* - * Initialize buffers for glink supported - * peripherals only. - */ - if (fwd_info->transport == TRANSPORT_GLINK) - diagfwd_write_buffers_init(fwd_info); - + diagfwd_write_buffers_init(fwd_info); if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->open) fwd_info->c_ops->open(fwd_info); for (i = 0; i < NUM_WRITE_BUFFERS; i++) { @@ -1277,9 +1224,6 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info) if (!fwd_info) return -EIO; - if (fwd_info->type == TYPE_CNTL) - flush_workqueue(driver->cntl_wq); - mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 0; if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close) @@ -1337,33 +1281,12 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt) if (ctxt == 1 && fwd_info->buf_1) { /* Buffer 1 for core PD is freed */ + atomic_set(&fwd_info->buf_1->in_busy, 0); fwd_info->cpd_len_1 = 0; - - if (peripheral == PERIPHERAL_LPASS) { - if (!fwd_info->upd_len_1_a && - !fwd_info->upd_len_2_a) - atomic_set(&fwd_info->buf_1->in_busy, 0); - } else if (peripheral == PERIPHERAL_MODEM) { - if (!fwd_info->upd_len_1_a) - atomic_set(&fwd_info->buf_1->in_busy, 0); - } else { - atomic_set(&fwd_info->buf_1->in_busy, 0); - } } else if (ctxt == 2 && fwd_info->buf_2) { /* Buffer 2 for core PD is freed */ + atomic_set(&fwd_info->buf_2->in_busy, 0); fwd_info->cpd_len_2 = 0; - - if (peripheral == PERIPHERAL_LPASS) { - if (!fwd_info->upd_len_1_b && - !fwd_info->upd_len_2_b) - atomic_set(&fwd_info->buf_2->in_busy, 0); - } else if (peripheral == PERIPHERAL_MODEM) { - if (!fwd_info->upd_len_1_b) - atomic_set(&fwd_info->buf_2->in_busy, 0); - } else { - atomic_set(&fwd_info->buf_2->in_busy, 0); - } - } else if (ctxt == 3 && fwd_info->buf_upd_1_a) { /* Buffer 1 for user pd 1 is freed */ atomic_set(&fwd_info->buf_upd_1_a->in_busy, 0); diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h index eda70dcfdcd9533d19f810093d8948d200504517..037eeebdeb35b30ee54782c948636f074eea797d 100644 --- a/drivers/char/diag/diagfwd_peripheral.h +++ b/drivers/char/diag/diagfwd_peripheral.h @@ -105,9 +105,6 @@ void diagfwd_early_open(uint8_t peripheral); void diagfwd_late_open(struct diagfwd_info *fwd_info); void diagfwd_close(uint8_t peripheral, uint8_t type); - -int diag_md_get_peripheral(int ctxt); - int diagfwd_register(uint8_t transport, uint8_t peripheral, uint8_t type, void *ctxt, struct diag_peripheral_ops *ops, struct diagfwd_info **fwd_ctxt); diff --git a/drivers/char/rdbg.c b/drivers/char/rdbg.c index 8161d77ca1940565190384913cee178371eb2074..0823ed78485e6115ea095d0f4252d1d8543d9fbe 100644 --- a/drivers/char/rdbg.c +++ b/drivers/char/rdbg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, 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 @@ -22,7 +22,7 @@ #include #include -#define SMP2P_NUM_PROCS 16 +#define SMP2P_NUM_PROCS 8 #define MAX_RETRIES 20 #define SM_VERSION 1 @@ -146,17 +146,9 @@ static struct processor_specific_info proc_info[SMP2P_NUM_PROCS] = { {"rdbg_adsp", SMEM_LC_DEBUGGER, 16*1024}, /*ADSP*/ {0}, /*SMP2P_RESERVED_PROC_1*/ {"rdbg_wcnss", 0, 0}, /*WCNSS*/ - {"rdbg_cdsp", SMEM_LC_DEBUGGER, 16*1024}, /*CDSP*/ - {NULL}, /*SMP2P_POWER_PROC*/ - {NULL}, /*SMP2P_TZ_PROC*/ - {NULL}, /*EMPTY*/ - {NULL}, /*EMPTY*/ - {NULL}, /*EMPTY*/ - {NULL}, /*EMPTY*/ - {NULL}, /*EMPTY*/ - {NULL}, /*EMPTY*/ - {NULL}, /*EMPTY*/ - {NULL} /*SMP2P_REMOTE_MOCK_PROC*/ + {0}, /*SMP2P_RESERVED_PROC_2*/ + {0}, /*SMP2P_POWER_PROC*/ + {0} /*SMP2P_REMOTE_MOCK_PROC*/ }; static int smq_blockmap_get(struct smq_block_map *block_map, diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 6d56877b2e0ab6b551f71ce9172f5e2858b5b66d..252142524ff21606687a51f5cfab829ccc83c7f6 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -36,60 +36,10 @@ static DEFINE_SPINLOCK(driver_lock); struct class *tpm_class; dev_t tpm_devt; -/** - * tpm_try_get_ops() - Get a ref to the tpm_chip - * @chip: Chip to ref - * - * The caller must already have some kind of locking to ensure that chip is - * valid. This function will lock the chip so that the ops member can be - * accessed safely. The locking prevents tpm_chip_unregister from - * completing, so it should not be held for long periods. - * - * Returns -ERRNO if the chip could not be got. - */ -int tpm_try_get_ops(struct tpm_chip *chip) -{ - int rc = -EIO; - - get_device(&chip->dev); - - down_read(&chip->ops_sem); - if (!chip->ops) - goto out_lock; - - if (!try_module_get(chip->dev.parent->driver->owner)) - goto out_lock; - - return 0; -out_lock: - up_read(&chip->ops_sem); - put_device(&chip->dev); - return rc; -} -EXPORT_SYMBOL_GPL(tpm_try_get_ops); - -/** - * tpm_put_ops() - Release a ref to the tpm_chip - * @chip: Chip to put - * - * This is the opposite pair to tpm_try_get_ops(). After this returns chip may - * be kfree'd. +/* + * tpm_chip_find_get - return tpm_chip for a given chip number + * @chip_num the device number for the chip */ -void tpm_put_ops(struct tpm_chip *chip) -{ - module_put(chip->dev.parent->driver->owner); - up_read(&chip->ops_sem); - put_device(&chip->dev); -} -EXPORT_SYMBOL_GPL(tpm_put_ops); - -/** - * tpm_chip_find_get() - return tpm_chip for a given chip number - * @chip_num: id to find - * - * The return'd chip has been tpm_try_get_ops'd and must be released via - * tpm_put_ops - */ struct tpm_chip *tpm_chip_find_get(int chip_num) { struct tpm_chip *pos, *chip = NULL; @@ -99,10 +49,10 @@ struct tpm_chip *tpm_chip_find_get(int chip_num) if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) continue; - /* rcu prevents chip from being free'd */ - if (!tpm_try_get_ops(pos)) + if (try_module_get(pos->pdev->driver->owner)) { chip = pos; - break; + break; + } } rcu_read_unlock(); return chip; @@ -124,41 +74,6 @@ static void tpm_dev_release(struct device *dev) kfree(chip); } - -/** - * tpm_class_shutdown() - prepare the TPM device for loss of power. - * @dev: device to which the chip is associated. - * - * Issues a TPM2_Shutdown command prior to loss of power, as required by the - * TPM 2.0 spec. - * Then, calls bus- and device- specific shutdown code. - * - * XXX: This codepath relies on the fact that sysfs is not enabled for - * TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2 - * has sysfs support enabled before TPM sysfs's implicit locking is fixed. - */ -static int tpm_class_shutdown(struct device *dev) -{ - struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); - - if (chip->flags & TPM_CHIP_FLAG_TPM2) { - down_write(&chip->ops_sem); - tpm2_shutdown(chip, TPM2_SU_CLEAR); - chip->ops = NULL; - up_write(&chip->ops_sem); - } - /* Allow bus- and device-specific code to run. Note: since chip->ops - * is NULL, more-specific shutdown code will not be able to issue TPM - * commands. - */ - if (dev->bus && dev->bus->shutdown) - dev->bus->shutdown(dev); - else if (dev->driver && dev->driver->shutdown) - dev->driver->shutdown(dev); - return 0; -} - - /** * tpmm_chip_alloc() - allocate a new struct tpm_chip instance * @dev: device to which the chip is associated @@ -179,7 +94,6 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, return ERR_PTR(-ENOMEM); mutex_init(&chip->tpm_mutex); - init_rwsem(&chip->ops_sem); INIT_LIST_HEAD(&chip->list); chip->ops = ops; @@ -198,12 +112,13 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num); + chip->pdev = dev; + dev_set_drvdata(dev, chip); chip->dev.class = tpm_class; - chip->dev.class->shutdown = tpm_class_shutdown; chip->dev.release = tpm_dev_release; - chip->dev.parent = dev; + chip->dev.parent = chip->pdev; #ifdef CONFIG_ACPI chip->dev.groups = chip->groups; #endif @@ -218,7 +133,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, device_initialize(&chip->dev); cdev_init(&chip->cdev, &tpm_fops); - chip->cdev.owner = dev->driver->owner; + chip->cdev.owner = chip->pdev->driver->owner; chip->cdev.kobj.parent = &chip->dev.kobj; devm_add_action(dev, (void (*)(void *)) put_device, &chip->dev); @@ -258,12 +173,6 @@ static int tpm_add_char_device(struct tpm_chip *chip) static void tpm_del_char_device(struct tpm_chip *chip) { cdev_del(&chip->cdev); - - /* Make the driver uncallable. */ - down_write(&chip->ops_sem); - chip->ops = NULL; - up_write(&chip->ops_sem); - device_del(&chip->dev); } @@ -327,8 +236,9 @@ int tpm_chip_register(struct tpm_chip *chip) chip->flags |= TPM_CHIP_FLAG_REGISTERED; if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { - rc = __compat_only_sysfs_link_entry_to_kobj( - &chip->dev.parent->kobj, &chip->dev.kobj, "ppi"); + rc = __compat_only_sysfs_link_entry_to_kobj(&chip->pdev->kobj, + &chip->dev.kobj, + "ppi"); if (rc && rc != -ENOENT) { tpm_chip_unregister(chip); return rc; @@ -349,9 +259,6 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); * Takes the chip first away from the list of available TPM chips and then * cleans up all the resources reserved by tpm_chip_register(). * - * Once this function returns the driver call backs in 'op's will not be - * running and will no longer start. - * * NOTE: This function should be only called before deinitializing chip * resources. */ @@ -366,7 +273,7 @@ void tpm_chip_unregister(struct tpm_chip *chip) synchronize_rcu(); if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) - sysfs_remove_link(&chip->dev.parent->kobj, "ppi"); + sysfs_remove_link(&chip->pdev->kobj, "ppi"); tpm1_chip_unregister(chip); tpm_del_char_device(chip); diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index 912ad30be5852f8a2145d0c1e56c03257bbbb211..4f3137d9a35e1f0c4016040293ab3db583fbdbd2 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -61,7 +61,7 @@ static int tpm_open(struct inode *inode, struct file *file) * by the check of is_open variable, which is protected * by driver_lock. */ if (test_and_set_bit(0, &chip->is_open)) { - dev_dbg(&chip->dev, "Another process owns this TPM\n"); + dev_dbg(chip->pdev, "Another process owns this TPM\n"); return -EBUSY; } @@ -79,6 +79,7 @@ static int tpm_open(struct inode *inode, struct file *file) INIT_WORK(&priv->work, timeout_work); file->private_data = priv; + get_device(chip->pdev); return 0; } @@ -136,18 +137,9 @@ static ssize_t tpm_write(struct file *file, const char __user *buf, return -EFAULT; } - /* atomic tpm command send and result receive. We only hold the ops - * lock during this period so that the tpm can be unregistered even if - * the char dev is held open. - */ - if (tpm_try_get_ops(priv->chip)) { - mutex_unlock(&priv->buffer_mutex); - return -EPIPE; - } + /* atomic tpm command send and result receive */ out_size = tpm_transmit(priv->chip, priv->data_buffer, sizeof(priv->data_buffer), 0); - - tpm_put_ops(priv->chip); if (out_size < 0) { mutex_unlock(&priv->buffer_mutex); return out_size; @@ -174,6 +166,7 @@ static int tpm_release(struct inode *inode, struct file *file) file->private_data = NULL; atomic_set(&priv->data_pending, 0); clear_bit(0, &priv->chip->is_open); + put_device(priv->chip->pdev); kfree(priv); return 0; } diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 8588f2e4b9afa161ac0ba370cc55104377b7138a..17abe52e6365b2363af3b4677615a726d412c051 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -343,7 +343,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, if (count == 0) return -ENODATA; if (count > bufsiz) { - dev_err(&chip->dev, + dev_err(chip->pdev, "invalid count value %x %zx\n", count, bufsiz); return -E2BIG; } @@ -353,7 +353,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { - dev_err(&chip->dev, + dev_err(chip->pdev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; } @@ -372,7 +372,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, goto out_recv; if (chip->ops->req_canceled(chip, status)) { - dev_err(&chip->dev, "Operation Canceled\n"); + dev_err(chip->pdev, "Operation Canceled\n"); rc = -ECANCELED; goto out; } @@ -382,14 +382,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, } while (time_before(jiffies, stop)); chip->ops->cancel(chip); - dev_err(&chip->dev, "Operation Timed out\n"); + dev_err(chip->pdev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: rc = chip->ops->recv(chip, (u8 *) buf, bufsiz); if (rc < 0) - dev_err(&chip->dev, + dev_err(chip->pdev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: if (!(flags & TPM_TRANSMIT_UNLOCKED)) @@ -416,7 +416,7 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, err = be32_to_cpu(header->return_code); if (err != 0 && desc) - dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, + dev_err(chip->pdev, "A TPM error (%d) occurred %s\n", err, desc); return err; @@ -514,7 +514,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. Execute a startup command. */ - dev_info(&chip->dev, "Issuing TPM_STARTUP"); + dev_info(chip->pdev, "Issuing TPM_STARTUP"); if (tpm_startup(chip, TPM_ST_CLEAR)) return rc; @@ -526,7 +526,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) 0, NULL); } if (rc) { - dev_err(&chip->dev, + dev_err(chip->pdev, "A TPM error (%zd) occurred attempting to determine the timeouts\n", rc); goto duration; @@ -565,7 +565,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) /* Report adjusted timeouts */ if (chip->vendor.timeout_adjusted) { - dev_info(&chip->dev, + dev_info(chip->pdev, HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", old_timeout[0], new_timeout[0], old_timeout[1], new_timeout[1], @@ -612,7 +612,7 @@ duration: chip->vendor.duration[TPM_MEDIUM] *= 1000; chip->vendor.duration[TPM_LONG] *= 1000; chip->vendor.duration_adjusted = true; - dev_info(&chip->dev, "Adjusting TPM timeout parameters."); + dev_info(chip->pdev, "Adjusting TPM timeout parameters."); } return 0; } @@ -687,7 +687,7 @@ int tpm_is_tpm2(u32 chip_num) rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; - tpm_put_ops(chip); + tpm_chip_put(chip); return rc; } @@ -716,7 +716,7 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) rc = tpm2_pcr_read(chip, pcr_idx, res_buf); else rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); - tpm_put_ops(chip); + tpm_chip_put(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_pcr_read); @@ -751,7 +751,7 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) if (chip->flags & TPM_CHIP_FLAG_TPM2) { rc = tpm2_pcr_extend(chip, pcr_idx, hash); - tpm_put_ops(chip); + tpm_chip_put(chip); return rc; } @@ -761,7 +761,7 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, "attempting extend a PCR value"); - tpm_put_ops(chip); + tpm_chip_put(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_pcr_extend); @@ -802,9 +802,7 @@ int tpm_do_selftest(struct tpm_chip *chip) * around 300ms while the self test is ongoing, keep trying * until the self test duration expires. */ if (rc == -ETIME) { - dev_info( - &chip->dev, HW_ERR - "TPM command timed out during continue self test"); + dev_info(chip->pdev, HW_ERR "TPM command timed out during continue self test"); msleep(delay_msec); continue; } @@ -814,7 +812,7 @@ int tpm_do_selftest(struct tpm_chip *chip) rc = be32_to_cpu(cmd.header.out.return_code); if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { - dev_info(&chip->dev, + dev_info(chip->pdev, "TPM is disabled/deactivated (0x%X)\n", rc); /* TPM is disabled and/or deactivated; driver can * proceed and TPM does handle commands for @@ -842,7 +840,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) rc = tpm_transmit_cmd(chip, cmd, buflen, 0, "attempting tpm_cmd"); - tpm_put_ops(chip); + tpm_chip_put(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_send); @@ -968,10 +966,10 @@ int tpm_pm_suspend(struct device *dev) } if (rc) - dev_err(&chip->dev, + dev_err(chip->pdev, "Error (%d) sending savestate before suspend\n", rc); else if (try > 0) - dev_warn(&chip->dev, "TPM savestate took %dms\n", + dev_warn(chip->pdev, "TPM savestate took %dms\n", try * TPM_TIMEOUT_RETRY); return rc; @@ -1025,7 +1023,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) if (chip->flags & TPM_CHIP_FLAG_TPM2) { err = tpm2_get_random(chip, out, max); - tpm_put_ops(chip); + tpm_chip_put(chip); return err; } @@ -1047,7 +1045,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) num_bytes -= recd; } while (retries-- && total < max); - tpm_put_ops(chip); + tpm_chip_put(chip); return total ? total : -EIO; } EXPORT_SYMBOL_GPL(tpm_get_random); @@ -1073,7 +1071,7 @@ int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload, rc = tpm2_seal_trusted(chip, payload, options); - tpm_put_ops(chip); + tpm_chip_put(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_seal_trusted); @@ -1099,8 +1097,7 @@ int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload, rc = tpm2_unseal_trusted(chip, payload, options); - tpm_put_ops(chip); - + tpm_chip_put(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_unseal_trusted); diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 6a4056a3f7ee8c2e959c075e0dbe24a3c97d42a7..f880856aa75e5885dffef99676cdf9a0277eddac 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -284,28 +284,16 @@ static const struct attribute_group tpm_dev_group = { int tpm_sysfs_add_device(struct tpm_chip *chip) { int err; - - /* XXX: If you wish to remove this restriction, you must first update - * tpm_sysfs to explicitly lock chip->ops. - */ - if (chip->flags & TPM_CHIP_FLAG_TPM2) - return 0; - - err = sysfs_create_group(&chip->dev.parent->kobj, + err = sysfs_create_group(&chip->pdev->kobj, &tpm_dev_group); if (err) - dev_err(&chip->dev, + dev_err(chip->pdev, "failed to create sysfs attributes, %d\n", err); return err; } void tpm_sysfs_del_device(struct tpm_chip *chip) { - /* The sysfs routines rely on an implicit tpm_try_get_ops, this - * function is called before ops is null'd and the sysfs core - * synchronizes this removal so that no callbacks are running or can - * run again - */ - sysfs_remove_group(&chip->dev.parent->kobj, &tpm_dev_group); + sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group); } diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e21e2c599e669c4853df09ed570538013913d388..2216861f89f108b089db387072c33bd7a689fa3e 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -171,16 +171,11 @@ enum tpm_chip_flags { }; struct tpm_chip { + struct device *pdev; /* Device stuff */ struct device dev; struct cdev cdev; - /* A driver callback under ops cannot be run unless ops_sem is held - * (sometimes implicitly, eg for the sysfs code). ops becomes null - * when the driver is unregistered, see tpm_try_get_ops. - */ - struct rw_semaphore ops_sem; const struct tpm_class_ops *ops; - unsigned int flags; int dev_num; /* /dev/tpm# */ @@ -206,6 +201,11 @@ struct tpm_chip { #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) +static inline void tpm_chip_put(struct tpm_chip *chip) +{ + module_put(chip->pdev->driver->owner); +} + static inline int tpm_read_index(int base, int index) { outb(index, base); @@ -517,9 +517,6 @@ extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, wait_queue_head_t *, bool); struct tpm_chip *tpm_chip_find_get(int chip_num); -__must_check int tpm_try_get_ops(struct tpm_chip *chip); -void tpm_put_ops(struct tpm_chip *chip); - extern struct tpm_chip *tpmm_chip_alloc(struct device *dev, const struct tpm_class_ops *ops); extern int tpm_chip_register(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 286bd090a4889a37ea3fead79572c889ef38502f..cb7e4f6b70ba7afc2608bd118c25204b7643663e 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -570,7 +570,7 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT); if (rc) { - dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n", + dev_warn(chip->pdev, "0x%08x was not flushed, out of memory\n", handle); return; } @@ -580,7 +580,7 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "flushing context"); if (rc) - dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle, + dev_warn(chip->pdev, "0x%08x was not flushed, rc=%d\n", handle, rc); tpm_buf_destroy(&buf); @@ -753,7 +753,7 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) * except print the error code on a system failure. */ if (rc < 0) - dev_warn(&chip->dev, "transmit returned %d while stopping the TPM", + dev_warn(chip->pdev, "transmit returned %d while stopping the TPM", rc); } EXPORT_SYMBOL_GPL(tpm2_shutdown); @@ -820,7 +820,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) * immediately. This is a workaround for that. */ if (rc == TPM2_RC_TESTING) { - dev_warn(&chip->dev, "Got RC_TESTING, ignoring\n"); + dev_warn(chip->pdev, "Got RC_TESTING, ignoring\n"); rc = 0; } diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index a48a878f791d9e65f28ae5b2580a59c3d8bcd3c2..dfadad0916a1e8685ca743713d6cae168c947af0 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -49,7 +49,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) for (i = 0; i < 6; i++) { status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(&chip->dev, "error reading header\n"); + dev_err(chip->pdev, "error reading header\n"); return -EIO; } *buf++ = ioread8(chip->vendor.iobase); @@ -60,12 +60,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) size = be32_to_cpu(*native_size); if (count < size) { - dev_err(&chip->dev, + dev_err(chip->pdev, "Recv size(%d) less than available space\n", size); for (; i < size; i++) { /* clear the waiting data anyway */ status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(&chip->dev, "error reading data\n"); + dev_err(chip->pdev, "error reading data\n"); return -EIO; } } @@ -76,7 +76,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) for (; i < size; i++) { status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(&chip->dev, "error reading data\n"); + dev_err(chip->pdev, "error reading data\n"); return -EIO; } *buf++ = ioread8(chip->vendor.iobase); @@ -86,7 +86,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) status = ioread8(chip->vendor.iobase + 1); if (status & ATML_STATUS_DATA_AVAIL) { - dev_err(&chip->dev, "data available is stuck\n"); + dev_err(chip->pdev, "data available is stuck\n"); return -EIO; } @@ -97,9 +97,9 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) { int i; - dev_dbg(&chip->dev, "tpm_atml_send:\n"); + dev_dbg(chip->pdev, "tpm_atml_send:\n"); for (i = 0; i < count; i++) { - dev_dbg(&chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); + dev_dbg(chip->pdev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); iowrite8(buf[i], chip->vendor.iobase); } diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index dd8f0eb3170a496e15783afd24955a4be89e8fe3..8dfb88b9739c197f01eb538157e450c67323debc 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -52,7 +52,7 @@ struct priv_data { static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) { struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev.parent); + struct i2c_client *client = to_i2c_client(chip->pdev); s32 status; priv->len = 0; @@ -62,7 +62,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) status = i2c_master_send(client, buf, len); - dev_dbg(&chip->dev, + dev_dbg(chip->pdev, "%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__, (int)min_t(size_t, 64, len), buf, len, status); return status; @@ -71,7 +71,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) { struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev.parent); + struct i2c_client *client = to_i2c_client(chip->pdev); struct tpm_output_header *hdr = (struct tpm_output_header *)priv->buffer; u32 expected_len; @@ -88,7 +88,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) return -ENOMEM; if (priv->len >= expected_len) { - dev_dbg(&chip->dev, + dev_dbg(chip->pdev, "%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__, (int)min_t(size_t, 64, expected_len), buf, count, expected_len); @@ -97,7 +97,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) } rc = i2c_master_recv(client, buf, expected_len); - dev_dbg(&chip->dev, + dev_dbg(chip->pdev, "%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__, (int)min_t(size_t, 64, expected_len), buf, count, expected_len); @@ -106,13 +106,13 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) static void i2c_atmel_cancel(struct tpm_chip *chip) { - dev_err(&chip->dev, "TPM operation cancellation was requested, but is not supported"); + dev_err(chip->pdev, "TPM operation cancellation was requested, but is not supported"); } static u8 i2c_atmel_read_status(struct tpm_chip *chip) { struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev.parent); + struct i2c_client *client = to_i2c_client(chip->pdev); int rc; /* The TPM fails the I2C read until it is ready, so we do the entire @@ -125,7 +125,7 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip) /* Once the TPM has completed the command the command remains readable * until another command is issued. */ rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer)); - dev_dbg(&chip->dev, + dev_dbg(chip->pdev, "%s: sts=%d", __func__, rc); if (rc <= 0) return 0; diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index f2aa99e34b4b0b975435e81cc9b5d2b9537b7bae..63d5d22e9e600c2e7dd1b4b0e83df61f36b6a2e5 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -446,7 +446,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) /* read first 10 bytes, including tag, paramsize, and result */ size = recv_data(chip, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { - dev_err(&chip->dev, "Unable to read header\n"); + dev_err(chip->pdev, "Unable to read header\n"); goto out; } @@ -459,14 +459,14 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) size += recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE); if (size < expected) { - dev_err(&chip->dev, "Unable to read remainder of result\n"); + dev_err(chip->pdev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); if (status & TPM_STS_DATA_AVAIL) { /* retry? */ - dev_err(&chip->dev, "Error left over data\n"); + dev_err(chip->pdev, "Error left over data\n"); size = -EIO; goto out; } diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index a1e1474dda306bb57485b6da61cf34226e13e00a..847f1597fe9b283557e45f5598da955a2dbb7f8f 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -96,13 +96,13 @@ static s32 i2c_nuvoton_write_buf(struct i2c_client *client, u8 offset, u8 size, /* read TPM_STS register */ static u8 i2c_nuvoton_read_status(struct tpm_chip *chip) { - struct i2c_client *client = to_i2c_client(chip->dev.parent); + struct i2c_client *client = to_i2c_client(chip->pdev); s32 status; u8 data; status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data); if (status <= 0) { - dev_err(&chip->dev, "%s() error return %d\n", __func__, + dev_err(chip->pdev, "%s() error return %d\n", __func__, status); data = TPM_STS_ERR_VAL; } @@ -127,13 +127,13 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data) /* write commandReady to TPM_STS register */ static void i2c_nuvoton_ready(struct tpm_chip *chip) { - struct i2c_client *client = to_i2c_client(chip->dev.parent); + struct i2c_client *client = to_i2c_client(chip->pdev); s32 status; /* this causes the current command to be aborted */ status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY); if (status < 0) - dev_err(&chip->dev, + dev_err(chip->pdev, "%s() fail to write TPM_STS.commandReady\n", __func__); } @@ -212,7 +212,7 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value, return 0; } while (time_before(jiffies, stop)); } - dev_err(&chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask, + dev_err(chip->pdev, "%s(%02x, %02x) -> timeout\n", __func__, mask, value); return -ETIMEDOUT; } @@ -240,7 +240,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client, &chip->vendor.read_queue) == 0) { burst_count = i2c_nuvoton_get_burstcount(client, chip); if (burst_count < 0) { - dev_err(&chip->dev, + dev_err(chip->pdev, "%s() fail to read burstCount=%d\n", __func__, burst_count); return -EIO; @@ -249,12 +249,12 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client, rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R, bytes2read, &buf[size]); if (rc < 0) { - dev_err(&chip->dev, + dev_err(chip->pdev, "%s() fail on i2c_nuvoton_read_buf()=%d\n", __func__, rc); return -EIO; } - dev_dbg(&chip->dev, "%s(%d):", __func__, bytes2read); + dev_dbg(chip->pdev, "%s(%d):", __func__, bytes2read); size += bytes2read; } @@ -264,7 +264,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client, /* Read TPM command results */ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) { - struct device *dev = chip->dev.parent; + struct device *dev = chip->pdev; struct i2c_client *client = to_i2c_client(dev); s32 rc; int expected, status, burst_count, retries, size = 0; @@ -334,7 +334,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) break; } i2c_nuvoton_ready(chip); - dev_dbg(&chip->dev, "%s() -> %d\n", __func__, size); + dev_dbg(chip->pdev, "%s() -> %d\n", __func__, size); return size; } @@ -347,7 +347,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) */ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len) { - struct device *dev = chip->dev.parent; + struct device *dev = chip->pdev; struct i2c_client *client = to_i2c_client(dev); u32 ordinal; size_t count = 0; diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index e3cf9f3545c57abfff68752effb73a4edff0c0bc..6c488e635fdd07ec9e5f885d8780a18595108b2d 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -195,9 +195,9 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) } if (i == TPM_MAX_TRIES) { /* timeout occurs */ if (wait_for_bit == STAT_XFE) - dev_err(&chip->dev, "Timeout in wait(STAT_XFE)\n"); + dev_err(chip->pdev, "Timeout in wait(STAT_XFE)\n"); if (wait_for_bit == STAT_RDA) - dev_err(&chip->dev, "Timeout in wait(STAT_RDA)\n"); + dev_err(chip->pdev, "Timeout in wait(STAT_RDA)\n"); return -EIO; } return 0; @@ -220,7 +220,7 @@ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) static void tpm_wtx(struct tpm_chip *chip) { number_of_wtx++; - dev_info(&chip->dev, "Granting WTX (%02d / %02d)\n", + dev_info(chip->pdev, "Granting WTX (%02d / %02d)\n", number_of_wtx, TPM_MAX_WTX_PACKAGES); wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_CTRL_WTX); @@ -231,7 +231,7 @@ static void tpm_wtx(struct tpm_chip *chip) static void tpm_wtx_abort(struct tpm_chip *chip) { - dev_info(&chip->dev, "Aborting WTX\n"); + dev_info(chip->pdev, "Aborting WTX\n"); wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_CTRL_WTX_ABORT); wait_and_send(chip, 0x00); @@ -257,7 +257,7 @@ recv_begin: } if (buf[0] != TPM_VL_VER) { - dev_err(&chip->dev, + dev_err(chip->pdev, "Wrong transport protocol implementation!\n"); return -EIO; } @@ -272,7 +272,7 @@ recv_begin: } if ((size == 0x6D00) && (buf[1] == 0x80)) { - dev_err(&chip->dev, "Error handling on vendor layer!\n"); + dev_err(chip->pdev, "Error handling on vendor layer!\n"); return -EIO; } @@ -284,7 +284,7 @@ recv_begin: } if (buf[1] == TPM_CTRL_WTX) { - dev_info(&chip->dev, "WTX-package received\n"); + dev_info(chip->pdev, "WTX-package received\n"); if (number_of_wtx < TPM_MAX_WTX_PACKAGES) { tpm_wtx(chip); goto recv_begin; @@ -295,14 +295,14 @@ recv_begin: } if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) { - dev_info(&chip->dev, "WTX-abort acknowledged\n"); + dev_info(chip->pdev, "WTX-abort acknowledged\n"); return size; } if (buf[1] == TPM_CTRL_ERROR) { - dev_err(&chip->dev, "ERROR-package received:\n"); + dev_err(chip->pdev, "ERROR-package received:\n"); if (buf[4] == TPM_INF_NAK) - dev_err(&chip->dev, + dev_err(chip->pdev, "-> Negative acknowledgement" " - retransmit command!\n"); return -EIO; @@ -321,7 +321,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) ret = empty_fifo(chip, 1); if (ret) { - dev_err(&chip->dev, "Timeout while clearing FIFO\n"); + dev_err(chip->pdev, "Timeout while clearing FIFO\n"); return -EIO; } diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 766370bed60c14a5c32e37661470c7e1f4c5f69c..289389ecef84f039d52689b9b56152bfef5f8593 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -113,7 +113,7 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) } while (time_before(jiffies, stop)); - dev_info(&chip->dev, "wait for ready failed\n"); + dev_info(chip->pdev, "wait for ready failed\n"); return -EBUSY; } @@ -129,12 +129,12 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) { - dev_err(&chip->dev, "F0 timeout\n"); + dev_err(chip->pdev, "F0 timeout\n"); return -EIO; } if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) { - dev_err(&chip->dev, "not in normal mode (0x%x)\n", + dev_err(chip->pdev, "not in normal mode (0x%x)\n", data); return -EIO; } @@ -143,7 +143,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) for (p = buffer; p < &buffer[count]; p++) { if (wait_for_stat (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) { - dev_err(&chip->dev, + dev_err(chip->pdev, "OBF timeout (while reading data)\n"); return -EIO; } @@ -154,11 +154,11 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) if ((data & NSC_STATUS_F0) == 0 && (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) { - dev_err(&chip->dev, "F0 not set\n"); + dev_err(chip->pdev, "F0 not set\n"); return -EIO; } if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) { - dev_err(&chip->dev, + dev_err(chip->pdev, "expected end of command(0x%x)\n", data); return -EIO; } @@ -189,19 +189,19 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(&chip->dev, "IBF timeout\n"); + dev_err(chip->pdev, "IBF timeout\n"); return -EIO; } outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND); if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) { - dev_err(&chip->dev, "IBR timeout\n"); + dev_err(chip->pdev, "IBR timeout\n"); return -EIO; } for (i = 0; i < count; i++) { if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(&chip->dev, + dev_err(chip->pdev, "IBF timeout (while writing data)\n"); return -EIO; } @@ -209,7 +209,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) } if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(&chip->dev, "IBF timeout\n"); + dev_err(chip->pdev, "IBF timeout\n"); return -EIO; } outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 7f13221aeb304dc21ce84fb73bc84cb0edbc8a06..f10a107614b47dab06df4ad2166fa3f321fda822 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -293,7 +293,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) /* read first 10 bytes, including tag, paramsize, and result */ if ((size = recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) { - dev_err(&chip->dev, "Unable to read header\n"); + dev_err(chip->pdev, "Unable to read header\n"); goto out; } @@ -306,7 +306,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) if ((size += recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE)) < expected) { - dev_err(&chip->dev, "Unable to read remainder of result\n"); + dev_err(chip->pdev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } @@ -315,7 +315,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) &chip->vendor.int_queue, false); status = tpm_tis_status(chip); if (status & TPM_STS_DATA_AVAIL) { /* retry? */ - dev_err(&chip->dev, "Error left over data\n"); + dev_err(chip->pdev, "Error left over data\n"); size = -EIO; goto out; } @@ -401,7 +401,7 @@ static void disable_interrupts(struct tpm_chip *chip) iowrite32(intmask, chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); - devm_free_irq(&chip->dev, chip->vendor.irq, chip); + devm_free_irq(chip->pdev, chip->vendor.irq, chip); chip->vendor.irq = 0; } @@ -463,7 +463,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) msleep(1); if (!priv->irq_tested) { disable_interrupts(chip); - dev_err(&chip->dev, + dev_err(chip->pdev, FW_BUG "TPM interrupt not working, polling instead\n"); } priv->irq_tested = true; @@ -533,7 +533,7 @@ static int probe_itpm(struct tpm_chip *chip) rc = tpm_tis_send_data(chip, cmd_getticks, len); if (rc == 0) { - dev_info(&chip->dev, "Detected an iTPM.\n"); + dev_info(chip->pdev, "Detected an iTPM.\n"); rc = 1; } else rc = -EFAULT; @@ -766,7 +766,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info, if (devm_request_irq (dev, i, tis_int_probe, IRQF_SHARED, chip->devname, chip) != 0) { - dev_info(&chip->dev, + dev_info(chip->pdev, "Unable to request irq: %d for probe\n", i); continue; @@ -818,7 +818,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info, if (devm_request_irq (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED, chip->devname, chip) != 0) { - dev_info(&chip->dev, + dev_info(chip->pdev, "Unable to request irq: %d for use\n", chip->vendor.irq); chip->vendor.irq = 0; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index be0b09a0fb44372a93e72cb9639198fdf8b569c4..31e8ae916ba0d8ec4425d33aca2ab7b08eb6e50a 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1864,7 +1864,7 @@ static void config_work_handler(struct work_struct *work) { struct ports_device *portdev; - portdev = container_of(work, struct ports_device, config_work); + portdev = container_of(work, struct ports_device, control_work); if (!use_multiport(portdev)) { struct virtio_device *vdev; struct port *port; diff --git a/drivers/clk/msm/clock-gcc-8998.c b/drivers/clk/msm/clock-gcc-8998.c index b1c8cc43769f823896c4b3383b2228b584ad02f9..e11d7e0e480aa1365e14bb305f3d7b934e7a6354 100644 --- a/drivers/clk/msm/clock-gcc-8998.c +++ b/drivers/clk/msm/clock-gcc-8998.c @@ -337,6 +337,18 @@ static struct clk_freq_tbl ftbl_blsp_qup_spi_apps_clk_src[] = { F_END }; +static struct clk_freq_tbl ftbl_blsp2_qup3_spi_apps_clk_src[] = { + F( 960000, cxo_clk_src, 10, 1, 2), + F( 4800000, cxo_clk_src, 4, 0, 0), + F( 9600000, cxo_clk_src, 2, 0, 0), + F( 15000000, gpll0_out_main, 10, 1, 4), + F( 19200000, cxo_clk_src, 1, 0, 0), + F( 25000000, gpll0_out_main, 12, 1, 2), + F( 30000000, gpll0_out_main, 10, 1, 2), + F( 50000000, gpll0_out_main, 12, 0, 0), + F_END +}; + static struct rcg_clk blsp1_qup1_spi_apps_clk_src = { .cmd_rcgr_reg = GCC_BLSP1_QUP1_SPI_APPS_CMD_RCGR, .set_rate = set_rate_mnd, @@ -636,7 +648,7 @@ static struct rcg_clk blsp2_qup3_i2c_apps_clk_src = { static struct rcg_clk blsp2_qup3_spi_apps_clk_src = { .cmd_rcgr_reg = GCC_BLSP2_QUP3_SPI_APPS_CMD_RCGR, .set_rate = set_rate_mnd, - .freq_tbl = ftbl_blsp_qup_spi_apps_clk_src, + .freq_tbl = ftbl_blsp2_qup3_spi_apps_clk_src, .current_freq = &rcg_dummy_freq, .base = &virt_base, .c = { diff --git a/drivers/clk/msm/clock-local2.c b/drivers/clk/msm/clock-local2.c index 40d8d12cda8206fff3bb1dc9492a9cc36e07da77..076ead6aaf345e251045a0b78ce5de2a1a73bd8c 100644 --- a/drivers/clk/msm/clock-local2.c +++ b/drivers/clk/msm/clock-local2.c @@ -1517,8 +1517,8 @@ static int set_rate_pixel(struct clk *clk, unsigned long rate) { struct rcg_clk *rcg = to_rcg_clk(clk); struct clk_freq_tbl *pixel_freq = rcg->current_freq; - int frac_num[] = {1, 2, 4, 3, 2}; - int frac_den[] = {1, 3, 9, 8, 9}; + int frac_num[] = {3, 2, 4, 1}; + int frac_den[] = {8, 9, 9, 1}; int delta = 100000; int i, rc; diff --git a/drivers/clk/msm/clock-mmss-8998.c b/drivers/clk/msm/clock-mmss-8998.c index fdaaa723accd83949c2a9104b008aa5212bb7949..cf4b738b3e605e1a2fc9e250d31a060c3896a4f9 100644 --- a/drivers/clk/msm/clock-mmss-8998.c +++ b/drivers/clk/msm/clock-mmss-8998.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -399,6 +404,9 @@ static struct rcg_clk maxi_clk_src = { static struct clk_freq_tbl ftbl_cpp_clk_src[] = { F_MM( 100000000, mmsscc_gpll0, 6, 0, 0), F_MM( 200000000, mmsscc_gpll0, 3, 0, 0), +#if defined(CONFIG_SONY_CAM_V4L2) + F_MM( 384000000, mmpll4_pll_out, 2, 0, 0), +#endif F_MM( 576000000, mmpll10_pll_out, 1, 0, 0), F_MM( 600000000, mmsscc_gpll0, 1, 0, 0), F_END diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c index eb72217b9b1caf4f0878445c08544c94d3b8feab..72a75873b810b5f94f45c1acc81cb49f382a3bca 100644 --- a/drivers/clk/msm/clock-osm.c +++ b/drivers/clk/msm/clock-osm.c @@ -397,7 +397,6 @@ struct clk_osm { u32 acd_extint1_cfg; u32 acd_autoxfer_ctl; u32 acd_debugfs_addr; - u32 acd_debugfs_addr_size; bool acd_init; bool secure_init; bool red_fsm_en; @@ -1450,7 +1449,6 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } pwrcl_clk.pbases[ACD_BASE] = pbase; - pwrcl_clk.acd_debugfs_addr_size = resource_size(res); pwrcl_clk.vbases[ACD_BASE] = vbase; pwrcl_clk.acd_init = true; } else { @@ -1468,7 +1466,6 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } perfcl_clk.pbases[ACD_BASE] = pbase; - perfcl_clk.acd_debugfs_addr_size = resource_size(res); perfcl_clk.vbases[ACD_BASE] = vbase; perfcl_clk.acd_init = true; } else { @@ -3018,11 +3015,6 @@ static int debugfs_get_debug_reg(void *data, u64 *val) { struct clk_osm *c = data; - if (!c->pbases[ACD_BASE]) { - pr_err("ACD base start not defined\n"); - return -EINVAL; - } - if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR) *val = readl_relaxed((char *)c->vbases[ACD_BASE] + c->acd_debugfs_addr); @@ -3035,11 +3027,6 @@ static int debugfs_set_debug_reg(void *data, u64 val) { struct clk_osm *c = data; - if (!c->pbases[ACD_BASE]) { - pr_err("ACD base start not defined\n"); - return -EINVAL; - } - if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR) clk_osm_acd_master_write_reg(c, val, c->acd_debugfs_addr); else @@ -3057,13 +3044,7 @@ static int debugfs_get_debug_reg_addr(void *data, u64 *val) { struct clk_osm *c = data; - if (!c->pbases[ACD_BASE]) { - pr_err("ACD base start not defined\n"); - return -EINVAL; - } - *val = c->acd_debugfs_addr; - return 0; } @@ -3071,16 +3052,7 @@ static int debugfs_set_debug_reg_addr(void *data, u64 val) { struct clk_osm *c = data; - if (!c->pbases[ACD_BASE]) { - pr_err("ACD base start not defined\n"); - return -EINVAL; - } - - if (val >= c->acd_debugfs_addr_size) - return -EINVAL; - c->acd_debugfs_addr = val; - return 0; } DEFINE_SIMPLE_ATTRIBUTE(debugfs_acd_debug_reg_addr_fops, diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c index 040707e58e252505a63085234cabe4f155859fd3..eb69ed35f46dae3c9c50ab29010c50f2fccec78e 100644 --- a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c @@ -152,6 +152,8 @@ struct dsi_pll_regs { struct dsi_pll_config { u32 ref_freq; + bool div_override; + u32 output_div; bool ignore_frac; bool disable_prescaler; bool enable_ssc; @@ -210,6 +212,7 @@ static void dsi_pll_setup_config(struct dsi_pll_8998 *pll, struct dsi_pll_config *config = &pll->pll_configuration; config->ref_freq = 19200000; + config->output_div = 1; config->dec_bits = 8; config->frac_bits = 18; config->lock_timer = 64; @@ -219,6 +222,7 @@ static void dsi_pll_setup_config(struct dsi_pll_8998 *pll, config->thresh_cycles = 32; config->refclk_cycles = 256; + config->div_override = false; config->ignore_frac = false; config->disable_prescaler = false; config->enable_ssc = rsc->ssc_en; @@ -239,14 +243,54 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_8998 *pll, { struct dsi_pll_config *config = &pll->pll_configuration; struct dsi_pll_regs *regs = &pll->reg_setup; + u64 target_freq; u64 fref = rsc->vco_ref_clk_rate; + u32 computed_output_div, div_log = 0; u64 pll_freq; u64 divider; u64 dec, dec_multiple; u32 frac; u64 multiplier; + u32 i; + + target_freq = rsc->vco_current_rate; + pr_debug("target_freq = %llu\n", target_freq); + + if (config->div_override) { + computed_output_div = config->output_div; + + /* + * Computed_output_div = 2 ^ div_log + * To get div_log from output div just get the index of the + * 1 bit in the value. + * div_log ranges from 0-3. so check the 4 lsbs + */ + + for (i = 0; i < 4; i++) { + if (computed_output_div & (1 << i)) { + div_log = i; + break; + } + } + + } else { + if (target_freq < MHZ_250) { + computed_output_div = 8; + div_log = 3; + } else if (target_freq < MHZ_500) { + computed_output_div = 4; + div_log = 2; + } else if (target_freq < MHZ_1000) { + computed_output_div = 2; + div_log = 1; + } else { + computed_output_div = 1; + div_log = 0; + } + } + pr_debug("computed_output_div = %d\n", computed_output_div); - pll_freq = rsc->vco_current_rate; + pll_freq = target_freq * computed_output_div; if (config->disable_prescaler) divider = fref; @@ -271,6 +315,7 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_8998 *pll, else regs->pll_clock_inverters = 0; + regs->pll_outdiv_rate = div_log; regs->pll_lockdet_rate = config->lock_timer; regs->decimal_div_start = dec; regs->frac_div_start_low = (frac & 0xff); @@ -433,6 +478,7 @@ static void dsi_pll_commit(struct dsi_pll_8998 *pll, MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1, reg->frac_div_start_high); MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x40); + MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate); MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06); MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10); MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters); @@ -551,23 +597,11 @@ static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) { int rc; struct mdss_pll_resources *rsc = vco->priv; - struct dsi_pll_8998 *pll = rsc->priv; - struct dsi_pll_regs *regs = &pll->reg_setup; dsi_pll_enable_pll_bias(rsc); if (rsc->slave) dsi_pll_enable_pll_bias(rsc->slave); - /* - * The PLL out dividers are fixed divider clocks and hence the - * set_div is not called during set_rate cycle of the tree. - * The outdiv rate is therefore set in the pll out mux's set_sel - * callback. But that will be called only after vco's set rate. - * Hence PLL out div value is set here before locking the PLL. - */ - MDSS_PLL_REG_W(rsc->pll_base, PLL_PLL_OUTDIV_RATE, - regs->pll_outdiv_rate); - /* Start PLL */ MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0x01); @@ -694,9 +728,7 @@ static int vco_8998_prepare(struct clk *c) static unsigned long dsi_pll_get_vco_rate(struct clk *c) { struct dsi_pll_vco_clk *vco = to_vco_clk(c); - struct mdss_pll_resources *rsc = vco->priv; - struct dsi_pll_8998 *pll = rsc->priv; - struct dsi_pll_regs *regs = &pll->reg_setup; + struct mdss_pll_resources *pll = vco->priv; int rc; u64 ref_clk = vco->ref_clk_rate; u64 vco_rate; @@ -706,30 +738,27 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c) u32 outdiv; u64 pll_freq, tmp64; - rc = mdss_pll_resource_enable(rsc, true); + rc = mdss_pll_resource_enable(pll, true); if (rc) { pr_err("failed to enable pll(%d) resource, rc=%d\n", - rsc->index, rc); + pll->index, rc); return 0; } - dec = MDSS_PLL_REG_R(rsc->pll_base, PLL_DECIMAL_DIV_START_1); + dec = MDSS_PLL_REG_R(pll->pll_base, PLL_DECIMAL_DIV_START_1); dec &= 0xFF; - frac = MDSS_PLL_REG_R(rsc->pll_base, PLL_FRAC_DIV_START_LOW_1); - frac |= ((MDSS_PLL_REG_R(rsc->pll_base, PLL_FRAC_DIV_START_MID_1) & + frac = MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_LOW_1); + frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_MID_1) & 0xFF) << 8); - frac |= ((MDSS_PLL_REG_R(rsc->pll_base, PLL_FRAC_DIV_START_HIGH_1) & + frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_HIGH_1) & 0x3) << 16); /* OUTDIV_1:0 field is (log(outdiv, 2)) */ - outdiv = MDSS_PLL_REG_R(rsc->pll_base, PLL_PLL_OUTDIV_RATE); + outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE); outdiv &= 0x3; - - regs->pll_outdiv_rate = outdiv; - outdiv = 1 << outdiv; /* @@ -747,7 +776,7 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c) pr_debug("dec=0x%x, frac=0x%x, outdiv=%d, vco=%llu\n", dec, frac, outdiv, vco_rate); - (void)mdss_pll_resource_enable(rsc, false); + (void)mdss_pll_resource_enable(pll, false); return (unsigned long)vco_rate; } @@ -901,26 +930,6 @@ static int bit_clk_set_div(struct div_clk *clk, int div) return rc; } -static int dsi_pll_out_set_mux_sel(struct mux_clk *clk, int sel) -{ - struct mdss_pll_resources *rsc = clk->priv; - struct dsi_pll_8998 *pll = rsc->priv; - struct dsi_pll_regs *regs = &pll->reg_setup; - - regs->pll_outdiv_rate = sel; - - return 0; -} - -static int dsi_pll_out_get_mux_sel(struct mux_clk *clk) -{ - struct mdss_pll_resources *rsc = clk->priv; - struct dsi_pll_8998 *pll = rsc->priv; - struct dsi_pll_regs *regs = &pll->reg_setup; - - return regs->pll_outdiv_rate; -} - static int post_vco_clk_get_div(struct div_clk *clk) { int rc; @@ -1116,75 +1125,52 @@ static struct clk_mux_ops mdss_mux_ops = { .get_mux_sel = mdss_get_mux_sel, }; -static struct clk_mux_ops mdss_pll_out_mux_ops = { - .set_mux_sel = dsi_pll_out_set_mux_sel, - .get_mux_sel = dsi_pll_out_get_mux_sel, -}; - /* * Clock tree for generating DSI byte and pixel clocks. * - * +---------------+ - * | vco_clk | - * | | - * +-------+-------+ - * | - * | - * +-------+--------+------------------+-----------------+ - * | | | | - * +------v-------+ +------v-------+ +-------v------+ +------v-------+ - * | pll_out_div1 | | pll_out_div2 | | pll_out_div4 | | pll_out_div8 | - * | DIV(1) | | DIV(2) | | DIV(4) | | DIV(8) | - * +------+-------+ +------+-------+ +-------+------+ +------+-------+ - * | | | | - * +------------+ | +--------------+ | - * | | | +---------------------------+ - * | | | | - * +--v---v---v----v--+ - * \ pll_out_mux / - * \ / - * +------+-----+ - * | - * +---------------+-----------------+ - * | | | - * +------v-----+ +-------v-------+ +-------v-------+ - * | bitclk_src | | post_vco_div1 | | post_vco_div4 | - * | DIV(1..15) | + DIV(1) | | DIV(4) | - * +------+-----+ +-------+-------+ +-------+-------+ - * | | | - * Shadow | | +---------------------+ - * Path | +-----------------------------+ | - * + | | | - * | +---------------------------------+ | | - * | | | | | - * | +------v------=+ +------v-------+ +-v---------v----+ - * | | byteclk_src | | post_bit_div | \ post_vco_mux / - * | | DIV(8) | | DIV(1,2) | \ / - * | +------+-------+ +------+-------+ +---+------+ - * | | | | - * | | | +----------+ - * | | | | - * | | +----v-----v------+ - * +-v--------v---------+ \ pclk_src_mux / - * \ byteclk_mux / \ / - * \ / +-----+-----+ - * +------+-------+ | Shadow - * | | Path - * v +-----v------+ + - * dsi_byte_clk | pclk_src | | - * | DIV(1..15) | | - * +-----+------+ | - * | | - * +------+ | - * | | - * +---v----v----+ - * \ pclk_mux / - * \ / - * +---+---+ - * | - * | - * v - * dsi_pclk + * + * +---------------+ + * | vco_clk | + * +-------+-------+ + * | + * +----------------------+------------------+ + * | | | + * +-------v-------+ +-------v-------+ +-------v-------+ + * | bitclk_src | | post_vco_div1 | | post_vco_div4 | + * | DIV(1..15) | +-------+-------+ +-------+-------+ + * +-------+-------+ | | + * | +------------+ | + * +--------------------+ | | + * Shadow Path | | | | + * + +-------v-------+ +------v------+ +---v-----v------+ + * | | byteclk_src | |post_bit_div | \ post_vco_mux / + * | | DIV(8) | |DIV(1,2) | \ / + * | +-------+-------+ +------+------+ +---+------+ + * | | | | + * | | +------+ +----+ + * | +--------+ | | + * | | +----v-----v------+ + * +-v---------v----+ \ pclk_src_mux / + * \ byteclk_mux / \ / + * \ / +-----+-----+ + * +----+-----+ | Shadow Path + * | | + + * v +-----v------+ | + * dsi_byte_clk | pclk_src | | + * | DIV(1..15) | | + * +-----+------+ | + * | | + * | | + * +--------+ | + * | | + * +---v----v----+ + * \ pclk_mux / + * \ / + * +---+---+ + * | + * | + * v + * dsi_pclk * */ @@ -1200,83 +1186,6 @@ static struct dsi_pll_vco_clk dsi0pll_vco_clk = { }, }; -static struct div_clk dsi0pll_pll_out_div1 = { - .data = { - .div = 1, - .min_div = 1, - .max_div = 1, - }, - .c = { - .parent = &dsi0pll_vco_clk.c, - .dbg_name = "dsi0pll_pll_out_div1", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_pll_out_div1.c), - } -}; - -static struct div_clk dsi0pll_pll_out_div2 = { - .data = { - .div = 2, - .min_div = 2, - .max_div = 2, - }, - .c = { - .parent = &dsi0pll_vco_clk.c, - .dbg_name = "dsi0pll_pll_out_div2", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_pll_out_div2.c), - } -}; - -static struct div_clk dsi0pll_pll_out_div4 = { - .data = { - .div = 4, - .min_div = 4, - .max_div = 4, - }, - .c = { - .parent = &dsi0pll_vco_clk.c, - .dbg_name = "dsi0pll_pll_out_div4", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_pll_out_div4.c), - } -}; - -static struct div_clk dsi0pll_pll_out_div8 = { - .data = { - .div = 8, - .min_div = 8, - .max_div = 8, - }, - .c = { - .parent = &dsi0pll_vco_clk.c, - .dbg_name = "dsi0pll_pll_out_div8", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_pll_out_div8.c), - } -}; - -static struct mux_clk dsi0pll_pll_out_mux = { - .num_parents = 4, - .parents = (struct clk_src[]) { - {&dsi0pll_pll_out_div1.c, 0}, - {&dsi0pll_pll_out_div2.c, 1}, - {&dsi0pll_pll_out_div4.c, 2}, - {&dsi0pll_pll_out_div8.c, 3}, - }, - .ops = &mdss_pll_out_mux_ops, - .c = { - .parent = &dsi0pll_pll_out_div1.c, - .dbg_name = "dsi0pll_pll_out_mux", - .ops = &clk_ops_gen_mux, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi0pll_pll_out_mux.c), - } -}; static struct div_clk dsi0pll_bitclk_src = { .data = { .div = 1, @@ -1285,7 +1194,7 @@ static struct div_clk dsi0pll_bitclk_src = { }, .ops = &clk_bitclk_src_ops, .c = { - .parent = &dsi0pll_pll_out_mux.c, + .parent = &dsi0pll_vco_clk.c, .dbg_name = "dsi0pll_bitclk_src", .ops = &clk_ops_bitclk_src_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1301,7 +1210,7 @@ static struct div_clk dsi0pll_post_vco_div1 = { }, .ops = &clk_post_vco_div_ops, .c = { - .parent = &dsi0pll_pll_out_mux.c, + .parent = &dsi0pll_vco_clk.c, .dbg_name = "dsi0pll_post_vco_div1", .ops = &clk_ops_post_vco_div_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1317,7 +1226,7 @@ static struct div_clk dsi0pll_post_vco_div4 = { }, .ops = &clk_post_vco_div_ops, .c = { - .parent = &dsi0pll_pll_out_mux.c, + .parent = &dsi0pll_vco_clk.c, .dbg_name = "dsi0pll_post_vco_div4", .ops = &clk_ops_post_vco_div_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1446,84 +1355,6 @@ static struct dsi_pll_vco_clk dsi1pll_vco_clk = { }, }; -static struct div_clk dsi1pll_pll_out_div1 = { - .data = { - .div = 1, - .min_div = 1, - .max_div = 1, - }, - .c = { - .parent = &dsi1pll_vco_clk.c, - .dbg_name = "dsi1pll_pll_out_div1", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_pll_out_div1.c), - } -}; - -static struct div_clk dsi1pll_pll_out_div2 = { - .data = { - .div = 2, - .min_div = 2, - .max_div = 2, - }, - .c = { - .parent = &dsi1pll_vco_clk.c, - .dbg_name = "dsi1pll_pll_out_div2", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_pll_out_div2.c), - } -}; - -static struct div_clk dsi1pll_pll_out_div4 = { - .data = { - .div = 4, - .min_div = 4, - .max_div = 4, - }, - .c = { - .parent = &dsi1pll_vco_clk.c, - .dbg_name = "dsi1pll_pll_out_div4", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_pll_out_div4.c), - } -}; - -static struct div_clk dsi1pll_pll_out_div8 = { - .data = { - .div = 8, - .min_div = 8, - .max_div = 8, - }, - .c = { - .parent = &dsi1pll_vco_clk.c, - .dbg_name = "dsi1pll_pll_out_div8", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_pll_out_div8.c), - } -}; - -static struct mux_clk dsi1pll_pll_out_mux = { - .num_parents = 4, - .parents = (struct clk_src[]) { - {&dsi1pll_pll_out_div1.c, 0}, - {&dsi1pll_pll_out_div2.c, 1}, - {&dsi1pll_pll_out_div4.c, 2}, - {&dsi1pll_pll_out_div8.c, 3}, - }, - .ops = &mdss_pll_out_mux_ops, - .c = { - .parent = &dsi1pll_pll_out_div1.c, - .dbg_name = "dsi1pll_pll_out_mux", - .ops = &clk_ops_gen_mux, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dsi1pll_pll_out_mux.c), - } -}; - static struct div_clk dsi1pll_bitclk_src = { .data = { .div = 1, @@ -1532,7 +1363,7 @@ static struct div_clk dsi1pll_bitclk_src = { }, .ops = &clk_bitclk_src_ops, .c = { - .parent = &dsi1pll_pll_out_mux.c, + .parent = &dsi1pll_vco_clk.c, .dbg_name = "dsi1pll_bitclk_src", .ops = &clk_ops_bitclk_src_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1548,7 +1379,7 @@ static struct div_clk dsi1pll_post_vco_div1 = { }, .ops = &clk_post_vco_div_ops, .c = { - .parent = &dsi1pll_pll_out_mux.c, + .parent = &dsi1pll_vco_clk.c, .dbg_name = "dsi1pll_post_vco_div1", .ops = &clk_ops_post_vco_div_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1564,7 +1395,7 @@ static struct div_clk dsi1pll_post_vco_div4 = { }, .ops = &clk_post_vco_div_ops, .c = { - .parent = &dsi1pll_pll_out_mux.c, + .parent = &dsi1pll_vco_clk.c, .dbg_name = "dsi1pll_post_vco_div4", .ops = &clk_ops_post_vco_div_c, .flags = CLKFLAG_NO_RATE_CACHE, @@ -1692,11 +1523,6 @@ static struct clk_lookup mdss_dsi_pll0cc_8998[] = { CLK_LIST(dsi0pll_post_vco_div1), CLK_LIST(dsi0pll_post_vco_div4), CLK_LIST(dsi0pll_bitclk_src), - CLK_LIST(dsi0pll_pll_out_mux), - CLK_LIST(dsi0pll_pll_out_div8), - CLK_LIST(dsi0pll_pll_out_div4), - CLK_LIST(dsi0pll_pll_out_div2), - CLK_LIST(dsi0pll_pll_out_div1), CLK_LIST(dsi0pll_vco_clk), }; static struct clk_lookup mdss_dsi_pll1cc_8998[] = { @@ -1710,11 +1536,6 @@ static struct clk_lookup mdss_dsi_pll1cc_8998[] = { CLK_LIST(dsi1pll_post_vco_div1), CLK_LIST(dsi1pll_post_vco_div4), CLK_LIST(dsi1pll_bitclk_src), - CLK_LIST(dsi1pll_pll_out_mux), - CLK_LIST(dsi1pll_pll_out_div8), - CLK_LIST(dsi1pll_pll_out_div4), - CLK_LIST(dsi1pll_pll_out_div2), - CLK_LIST(dsi1pll_pll_out_div1), CLK_LIST(dsi1pll_vco_clk), }; @@ -1775,11 +1596,6 @@ int dsi_pll_clock_register_8998(struct platform_device *pdev, dsi0pll_post_vco_div1.priv = pll_res; dsi0pll_post_vco_div4.priv = pll_res; dsi0pll_bitclk_src.priv = pll_res; - dsi0pll_pll_out_div1.priv = pll_res; - dsi0pll_pll_out_div2.priv = pll_res; - dsi0pll_pll_out_div4.priv = pll_res; - dsi0pll_pll_out_div8.priv = pll_res; - dsi0pll_pll_out_mux.priv = pll_res; dsi0pll_vco_clk.priv = pll_res; rc = of_msm_clock_register(pdev->dev.of_node, @@ -1796,11 +1612,6 @@ int dsi_pll_clock_register_8998(struct platform_device *pdev, dsi1pll_post_vco_div1.priv = pll_res; dsi1pll_post_vco_div4.priv = pll_res; dsi1pll_bitclk_src.priv = pll_res; - dsi1pll_pll_out_div1.priv = pll_res; - dsi1pll_pll_out_div2.priv = pll_res; - dsi1pll_pll_out_div4.priv = pll_res; - dsi1pll_pll_out_div8.priv = pll_res; - dsi1pll_pll_out_mux.priv = pll_res; dsi1pll_vco_clk.priv = pll_res; rc = of_msm_clock_register(pdev->dev.of_node, diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c index 510a9803bd820041d4787b51ef6de5de861f95e0..d99e13817a29bb7b51fcfadc2a00c1b08a95e648 100644 --- a/drivers/clk/qcom/clk-cpu-osm.c +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -226,8 +226,8 @@ enum clk_osm_trace_packet_id { #define PLL_DD_D0_USER_CTL_LO 0x17916208 #define PLL_DD_D1_USER_CTL_LO 0x17816208 -#define PWRCL_EFUSE_SHIFT 29 -#define PWRCL_EFUSE_MASK 0x7 +#define PWRCL_EFUSE_SHIFT 0 +#define PWRCL_EFUSE_MASK 0 #define PERFCL_EFUSE_SHIFT 29 #define PERFCL_EFUSE_MASK 0x7 @@ -384,7 +384,6 @@ struct clk_osm { u32 acd_extint1_cfg; u32 acd_autoxfer_ctl; u32 acd_debugfs_addr; - u32 acd_debugfs_addr_size; bool acd_init; bool secure_init; bool red_fsm_en; @@ -623,21 +622,18 @@ static inline bool is_better_rate(unsigned long req, unsigned long best, return (req <= new && new < best) || (best < req && best < new); } -static int clk_osm_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) +static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) { int i; unsigned long rrate = 0; - unsigned long rate = req->rate; /* * If the rate passed in is 0, return the first frequency in the * FMAX table. */ - if (!rate) { - req->rate = hw->init->rate_max[0]; - return 0; - } + if (!rate) + return hw->init->rate_max[0]; for (i = 0; i < hw->init->num_rate_max; i++) { if (is_better_rate(rate, rrate, hw->init->rate_max[i])) { @@ -647,12 +643,10 @@ static int clk_osm_determine_rate(struct clk_hw *hw, } } - req->rate = rrate; - pr_debug("%s: rate %lu, rrate %ld, Rate max %ld\n", __func__, rate, rrate, hw->init->rate_max[i]); - return 0; + return rrate; } static int clk_osm_search_table(struct osm_entry *table, int entries, long rate) @@ -683,19 +677,18 @@ static int clk_osm_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_osm *cpuclk = to_clk_osm(hw); int index = 0; - struct clk_rate_request req; + unsigned long r_rate; - req.rate = rate; - clk_osm_determine_rate(hw, &req); + r_rate = clk_osm_round_rate(hw, rate, NULL); - if (rate != req.rate) { + if (rate != r_rate) { pr_err("invalid rate requested rate=%ld\n", rate); return -EINVAL; } /* Convert rate to table index */ index = clk_osm_search_table(cpuclk->osm_table, - cpuclk->num_entries, req.rate); + cpuclk->num_entries, r_rate); if (index < 0) { pr_err("cannot set cluster %u to %lu\n", cpuclk->cluster_num, rate); @@ -779,7 +772,7 @@ static unsigned long clk_osm_recalc_rate(struct clk_hw *hw, static struct clk_ops clk_ops_cpu_osm = { .enable = clk_osm_enable, .set_rate = clk_osm_set_rate, - .determine_rate = clk_osm_determine_rate, + .round_rate = clk_osm_round_rate, .list_rate = clk_osm_list_rate, .recalc_rate = clk_osm_recalc_rate, .debug_init = clk_debug_measure_add, @@ -1378,7 +1371,6 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } pwrcl_clk.pbases[ACD_BASE] = pbase; - pwrcl_clk.acd_debugfs_addr_size = resource_size(res); pwrcl_clk.vbases[ACD_BASE] = vbase; pwrcl_clk.acd_init = true; } else { @@ -1396,7 +1388,6 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } perfcl_clk.pbases[ACD_BASE] = pbase; - perfcl_clk.acd_debugfs_addr_size = resource_size(res); perfcl_clk.vbases[ACD_BASE] = vbase; perfcl_clk.acd_init = true; } else { @@ -2841,11 +2832,6 @@ static int debugfs_get_debug_reg(void *data, u64 *val) { struct clk_osm *c = data; - if (!c->pbases[ACD_BASE]) { - pr_err("ACD base start not defined\n"); - return -EINVAL; - } - if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR) *val = readl_relaxed((char *)c->vbases[ACD_BASE] + c->acd_debugfs_addr); @@ -2858,11 +2844,6 @@ static int debugfs_set_debug_reg(void *data, u64 val) { struct clk_osm *c = data; - if (!c->pbases[ACD_BASE]) { - pr_err("ACD base start not defined\n"); - return -EINVAL; - } - if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR) clk_osm_acd_master_write_reg(c, val, c->acd_debugfs_addr); else @@ -2880,13 +2861,7 @@ static int debugfs_get_debug_reg_addr(void *data, u64 *val) { struct clk_osm *c = data; - if (!c->pbases[ACD_BASE]) { - pr_err("ACD base start not defined\n"); - return -EINVAL; - } - *val = c->acd_debugfs_addr; - return 0; } @@ -2894,14 +2869,6 @@ static int debugfs_set_debug_reg_addr(void *data, u64 val) { struct clk_osm *c = data; - if (!c->pbases[ACD_BASE]) { - pr_err("ACD base start not defined\n"); - return -EINVAL; - } - - if (val >= c->acd_debugfs_addr_size) - return -EINVAL; - c->acd_debugfs_addr = val; return 0; } diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index abbee61c99c83e134b6651386e355827b1559d75..6b3dcf1564d078162cfc995702b95b94dd5aef08 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -15,6 +15,11 @@ * Author: Mike Chan (mike@android.com) * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -35,6 +40,37 @@ #define CREATE_TRACE_POINTS #include +#ifdef CONFIG_SCHED_HMP +struct cluster { + struct list_head list; + struct task_struct *speedchange_task; + spinlock_t speedchange_cpumask_lock; + cpumask_t speedchange_cpumask; + cpumask_t cpus; + int id; +}; + +static LIST_HEAD(cluster_list_head); + +#define for_each_cluster(cluster) \ + list_for_each_entry(cluster, &cluster_list_head, list) + +#define for_each_cluster_safe(cluster, tmp) \ + list_for_each_entry_safe(cluster, tmp, \ + &cluster_list_head, list) + +static void assign_cluster_ids(void) +{ + struct cluster *clstr; + int pos = 0; + + for_each_cluster(clstr) { + clstr->id = pos; + pos++; + } +} +#endif + struct cpufreq_interactive_policyinfo { struct timer_list policy_timer; struct timer_list policy_slack_timer; @@ -53,11 +89,14 @@ struct cpufreq_interactive_policyinfo { u64 max_freq_hyst_start_time; struct rw_semaphore enable_sem; bool reject_notification; - bool notif_pending; + atomic_t notif_pending; unsigned long notif_cpu; int governor_enabled; struct cpufreq_interactive_tunables *cached_tunables; struct sched_load *sl; +#ifdef CONFIG_SCHED_HMP + struct cluster *cluster; +#endif }; /* Protected by per-policy load_lock */ @@ -72,16 +111,18 @@ struct cpufreq_interactive_cpuinfo { static DEFINE_PER_CPU(struct cpufreq_interactive_policyinfo *, polinfo); static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo); +#ifndef CONFIG_SCHED_HMP /* realtime thread handles frequency scaling */ static struct task_struct *speedchange_task; static cpumask_t speedchange_cpumask; static spinlock_t speedchange_cpumask_lock; -static struct mutex gov_lock; +#endif static int set_window_count; static int migration_register_count; static struct mutex sched_lock; static cpumask_t controlled_cpus; +static struct mutex gov_lock; /* Target load. Lower values result in higher CPU speeds. */ #define DEFAULT_TARGET_LOAD 90 @@ -479,7 +520,10 @@ static void cpufreq_interactive_timer(unsigned long data) bool skip_hispeed_logic, skip_min_sample_time; bool jump_to_max_no_ts = false; bool jump_to_max = false; - bool start_hyst = true; + bool notif_pending = false; +#ifdef CONFIG_SCHED_HMP + struct cluster *clstr; +#endif if (!down_read_trylock(&ppol->enable_sem)) return; @@ -491,10 +535,15 @@ static void cpufreq_interactive_timer(unsigned long data) spin_lock_irqsave(&ppol->target_freq_lock, flags); spin_lock(&ppol->load_lock); + if (atomic_read(&ppol->notif_pending)) { + (void) hrtimer_try_to_cancel(&ppol->notif_timer); + atomic_set(&ppol->notif_pending, 0); + notif_pending = true; + } + skip_hispeed_logic = - tunables->ignore_hispeed_on_notif && ppol->notif_pending; - skip_min_sample_time = tunables->fast_ramp_down && ppol->notif_pending; - ppol->notif_pending = false; + tunables->ignore_hispeed_on_notif && notif_pending; + skip_min_sample_time = tunables->fast_ramp_down && notif_pending; now = ktime_to_us(ktime_get()); ppol->last_evaluated_jiffy = get_jiffies_64(); @@ -589,12 +638,8 @@ static void cpufreq_interactive_timer(unsigned long data) } if (now - ppol->max_freq_hyst_start_time < - tunables->max_freq_hysteresis) { - if (new_freq < ppol->policy->max && - ppol->policy->max <= tunables->hispeed_freq) - start_hyst = false; + tunables->max_freq_hysteresis) new_freq = max(tunables->hispeed_freq, new_freq); - } if (!skip_hispeed_logic && ppol->target_freq >= tunables->hispeed_freq && @@ -651,7 +696,7 @@ static void cpufreq_interactive_timer(unsigned long data) ppol->floor_validate_time = now; } - if (start_hyst && new_freq >= ppol->policy->max && !jump_to_max_no_ts) + if (new_freq >= ppol->policy->max && !jump_to_max_no_ts) ppol->max_freq_hyst_start_time = now; if (ppol->target_freq == new_freq && @@ -668,10 +713,24 @@ static void cpufreq_interactive_timer(unsigned long data) ppol->target_freq = new_freq; spin_unlock_irqrestore(&ppol->target_freq_lock, flags); + +#ifdef CONFIG_SCHED_HMP + /* + * per cluster == per policy. Each cluster has own policy. + */ + clstr = ppol->cluster; + if (clstr) { + spin_lock_irqsave(&clstr->speedchange_cpumask_lock, flags); + cpumask_set_cpu(max_cpu, &clstr->speedchange_cpumask); + spin_unlock_irqrestore(&clstr->speedchange_cpumask_lock, flags); + wake_up_process_no_notif(clstr->speedchange_task); + } +#else spin_lock_irqsave(&speedchange_cpumask_lock, flags); cpumask_set_cpu(max_cpu, &speedchange_cpumask); spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); wake_up_process_no_notif(speedchange_task); +#endif rearm: if (!timer_pending(&ppol->policy_timer)) @@ -698,6 +757,69 @@ exit: return; } +#ifdef CONFIG_SCHED_HMP +static void update_cpus_freq_in_mask(cpumask_t *mask) +{ + struct cpufreq_interactive_policyinfo *ppol; + unsigned int cpu; + + for_each_cpu(cpu, mask) { + ppol = per_cpu(polinfo, cpu); + if (!down_read_trylock(&ppol->enable_sem)) + continue; + + if (!ppol->governor_enabled) { + up_read(&ppol->enable_sem); + continue; + } + + if (ppol->target_freq != ppol->policy->cur) { + trace_cpufreq_interactive_setspeed(cpu, + ppol->target_freq, + ppol->policy->cur); + __cpufreq_driver_target(ppol->policy, + ppol->target_freq, + CPUFREQ_RELATION_H); + } + + up_read(&ppol->enable_sem); + } +} + +static int speed_change_task_hmp(void *data) +{ + struct cluster *clstr = (struct cluster *) data; + cpumask_t tmp_mask; + unsigned long flags; + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&clstr->speedchange_cpumask_lock, flags); + + if (cpumask_empty(&clstr->speedchange_cpumask)) { + spin_unlock_irqrestore( + &clstr->speedchange_cpumask_lock, flags); + schedule(); + + if (kthread_should_stop()) + break; + + spin_lock_irqsave( + &clstr->speedchange_cpumask_lock, flags); + } + + set_current_state(TASK_RUNNING); + tmp_mask = clstr->speedchange_cpumask; + cpumask_clear(&clstr->speedchange_cpumask); + spin_unlock_irqrestore( + &clstr->speedchange_cpumask_lock, flags); + + update_cpus_freq_in_mask(&tmp_mask); + } + + return 0; +} +#else static int cpufreq_interactive_speedchange_task(void *data) { unsigned int cpu; @@ -747,16 +869,60 @@ static int cpufreq_interactive_speedchange_task(void *data) return 0; } +#endif /* CONFIG_SCHED_HMP */ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunables) { +#ifdef CONFIG_SCHED_HMP + struct cluster *clstr; +#else int i; +#endif int anyboost = 0; unsigned long flags[2]; struct cpufreq_interactive_policyinfo *ppol; tunables->boosted = true; +#ifdef CONFIG_SCHED_HMP + for_each_cluster(clstr) { + cpumask_t cluster_online_cpus = CPU_MASK_NONE; + int cfcpu; + + cpumask_and(&cluster_online_cpus, &clstr->cpus, cpu_online_mask); + cfcpu = cpumask_first(&cluster_online_cpus); + anyboost = 0; + + ppol = per_cpu(polinfo, cfcpu); + if (!ppol || tunables != ppol->policy->governor_data) + continue; + + spin_lock_irqsave(&clstr->speedchange_cpumask_lock, flags[0]); + spin_lock(&ppol->target_freq_lock); + + if (ppol->target_freq < tunables->hispeed_freq) { + ppol->target_freq = tunables->hispeed_freq; + cpumask_set_cpu(cfcpu, &clstr->speedchange_cpumask); + ppol->hispeed_validate_time = + ktime_to_us(ktime_get()); + anyboost = 1; + } + + /* + * Set floor freq and (re)start timer for when last + * validated. + */ + + ppol->floor_freq = tunables->hispeed_freq; + ppol->floor_validate_time = ktime_to_us(ktime_get()); + + spin_unlock(&ppol->target_freq_lock); + spin_unlock_irqrestore(&clstr->speedchange_cpumask_lock, flags[0]); + + if (anyboost) + wake_up_process_no_notif(clstr->speedchange_task); + } +#else spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]); for_each_online_cpu(i) { @@ -788,6 +954,7 @@ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunab if (anyboost) wake_up_process_no_notif(speedchange_task); +#endif } static int load_change_callback(struct notifier_block *nb, unsigned long val, @@ -796,7 +963,6 @@ static int load_change_callback(struct notifier_block *nb, unsigned long val, unsigned long cpu = (unsigned long) data; struct cpufreq_interactive_policyinfo *ppol = per_cpu(polinfo, cpu); struct cpufreq_interactive_tunables *tunables; - unsigned long flags; if (!ppol || ppol->reject_notification) return 0; @@ -810,14 +976,13 @@ static int load_change_callback(struct notifier_block *nb, unsigned long val, if (!tunables->use_sched_load || !tunables->use_migration_notif) goto exit; - spin_lock_irqsave(&ppol->target_freq_lock, flags); - ppol->notif_pending = true; - ppol->notif_cpu = cpu; - spin_unlock_irqrestore(&ppol->target_freq_lock, flags); + if (!atomic_cmpxchg(&ppol->notif_pending, 0, 1)) { + ppol->notif_cpu = cpu; + if (!hrtimer_is_queued(&ppol->notif_timer)) + hrtimer_start(&ppol->notif_timer, ms_to_ktime(1), + HRTIMER_MODE_REL); + } - if (!hrtimer_is_queued(&ppol->notif_timer)) - hrtimer_start(&ppol->notif_timer, ms_to_ktime(1), - HRTIMER_MODE_REL); exit: up_read(&ppol->enable_sem); return 0; @@ -830,18 +995,29 @@ static enum hrtimer_restart cpufreq_interactive_hrtimer(struct hrtimer *timer) int cpu; if (!down_read_trylock(&ppol->enable_sem)) - return 0; - if (!ppol->governor_enabled) { - up_read(&ppol->enable_sem); - return 0; - } + goto no_restart; + + if (!ppol->governor_enabled) + goto up_read_no_restart; + + /* + * We race here with a policy timer, but it is not + * a big issue. Just leave the callback, because + * notification has already been handled by the + * normal periodic timer. + */ + if (!atomic_read(&ppol->notif_pending)) + goto up_read_no_restart; + cpu = ppol->notif_cpu; trace_cpufreq_interactive_load_change(cpu); del_timer(&ppol->policy_timer); del_timer(&ppol->policy_slack_timer); cpufreq_interactive_timer(cpu); +up_read_no_restart: up_read(&ppol->enable_sem); +no_restart: return HRTIMER_NORESTART; } @@ -1649,6 +1825,88 @@ static struct cpufreq_interactive_tunables *get_tunables( return cached_common_tunables; } +#ifdef CONFIG_SCHED_HMP +static int hmp_register_cluster(cpumask_t *assign_mask) +{ + struct cpufreq_interactive_policyinfo *ppol; + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + struct cluster *clstr; + int i; + + /* + * check if already exists or not + */ + for_each_cluster(clstr) { + if (cpumask_intersects(assign_mask, &clstr->cpus)) + goto leave; + } + + clstr = kzalloc(sizeof(*clstr), GFP_KERNEL); + if (!clstr) + return -ENOMEM; + + /* + * set cluster's mask cpus it is responsible for + */ + cpumask_copy(&clstr->cpus, assign_mask); + spin_lock_init(&clstr->speedchange_cpumask_lock); + + for_each_cpu(i, assign_mask) { + ppol = per_cpu(polinfo, i); + ppol->cluster = clstr; + } + + clstr->speedchange_cpumask = CPU_MASK_NONE; + clstr->speedchange_task = kthread_create(speed_change_task_hmp, + clstr, "cfinteractive"); + + if (IS_ERR(clstr->speedchange_task)) + return PTR_ERR(clstr->speedchange_task); + + sched_setscheduler_nocheck(clstr->speedchange_task, + SCHED_FIFO, ¶m); + get_task_struct(clstr->speedchange_task); + + /* + * add our new cluster to the list + */ + INIT_LIST_HEAD(&clstr->list); + list_add_tail(&clstr->list, &cluster_list_head); + assign_cluster_ids(); + + wake_up_process_no_notif(clstr->speedchange_task); + + pr_info("-> added cluster_%d with %d CPUs\n", + clstr->id, cpumask_weight(&clstr->cpus)); + +leave: + return 0; +} + +static void hmp_unregister_cluster(struct cluster *clstr) +{ + struct cpufreq_interactive_policyinfo *ppol; + int i; + + if (clstr) { + kthread_stop(clstr->speedchange_task); + put_task_struct(clstr->speedchange_task); + + for_each_cpu(i, &clstr->cpus) { + ppol = per_cpu(polinfo, i); + ppol->cluster = NULL; + } + + list_del(&clstr->list); + + pr_info("-> remove cluster_%d with %d CPUs\n", + clstr->id, cpumask_weight(&clstr->cpus)); + + kzfree(clstr); + } +} +#endif /* CONFIG_SCHED_HMP */ + static int cpufreq_governor_interactive(struct cpufreq_policy *policy, unsigned int event) { @@ -1719,6 +1977,14 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, else cached_common_tunables = tunables; +#ifdef CONFIG_SCHED_HMP + mutex_lock(&gov_lock); + rc = hmp_register_cluster(policy->related_cpus); + mutex_unlock(&gov_lock); + + if (rc) + return rc; +#endif break; case CPUFREQ_GOV_POLICY_EXIT: @@ -1762,7 +2028,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, ppol->hispeed_validate_time = ppol->floor_validate_time; ppol->min_freq = policy->min; ppol->reject_notification = true; - ppol->notif_pending = false; + atomic_set(&ppol->notif_pending, 0); down_write(&ppol->enable_sem); del_timer_sync(&ppol->policy_timer); del_timer_sync(&ppol->policy_slack_timer); @@ -1824,11 +2090,16 @@ struct cpufreq_governor cpufreq_gov_interactive = { static int __init cpufreq_interactive_init(void) { +#ifndef CONFIG_SCHED_HMP struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; +#endif - spin_lock_init(&speedchange_cpumask_lock); mutex_init(&gov_lock); mutex_init(&sched_lock); + +#ifndef CONFIG_SCHED_HMP + spin_lock_init(&speedchange_cpumask_lock); + speedchange_task = kthread_create(cpufreq_interactive_speedchange_task, NULL, "cfinteractive"); @@ -1840,6 +2111,7 @@ static int __init cpufreq_interactive_init(void) /* NB: wake up so the thread does not look hung to the freezer */ wake_up_process_no_notif(speedchange_task); +#endif return cpufreq_register_governor(&cpufreq_gov_interactive); } @@ -1855,8 +2127,18 @@ static void __exit cpufreq_interactive_exit(void) int cpu; cpufreq_unregister_governor(&cpufreq_gov_interactive); +#ifdef CONFIG_SCHED_HMP + { + struct cluster *clstr, *tmp; + + for_each_cluster_safe(clstr, tmp) { + hmp_unregister_cluster(clstr); + } + } +#else kthread_stop(speedchange_task); put_task_struct(speedchange_task); +#endif for_each_possible_cpu(cpu) free_policyinfo(cpu); diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index 5b2db3c6568f691429fce3d636ac955e06b0bec9..d6d425773fa497274301eaa88f247fb8dd770e89 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c @@ -400,6 +400,7 @@ static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy) rate = clk_get_rate(s3c_freq->hclk); if (rate < 133 * 1000 * 1000) { pr_err("cpufreq: HCLK not at 133MHz\n"); + clk_put(s3c_freq->hclk); ret = -EINVAL; goto err_armclk; } diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 7abe908427dfc3e669bde0e37190360437610a15..0dadb6332f0eb7621875a9f35526a33581e50cd8 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -963,9 +963,7 @@ static int atmel_sha_finup(struct ahash_request *req) ctx->flags |= SHA_FLAGS_FINUP; err1 = atmel_sha_update(req); - if (err1 == -EINPROGRESS || - (err1 == -EBUSY && (ahash_request_flags(req) & - CRYPTO_TFM_REQ_MAY_BACKLOG))) + if (err1 == -EINPROGRESS || err1 == -EBUSY) return err1; /* diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index e06cc5df30be66b9c0dc7d737477203a03e210a4..99d5e11db194d4ecb0557949b0fd2dfcb0d59dc4 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -498,7 +498,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result); if (!ret) { /* in progress */ - wait_for_completion(&result.completion); + wait_for_completion_interruptible(&result.completion); ret = result.err; #ifdef DEBUG print_hex_dump(KERN_ERR, diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index 3ce1d5cdcbd22ec18677b48c40b2b008c4d7d657..e1eaf4ff9762646acac020c85c77bb122c570f0e 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -103,7 +103,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result); if (!ret) { /* in progress */ - wait_for_completion(&result.completion); + wait_for_completion_interruptible(&result.completion); ret = result.err; #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 68b6a26f00b87a5d69ab025639a257e437117dba..a60993684a5c20e107e953bd75a91e3ad67b8f97 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -869,7 +874,7 @@ static int qcom_ice_restore_key_config(struct ice_device *ice_dev) static int qcom_ice_init_clocks(struct ice_device *ice) { int ret = -EINVAL; - struct ice_clk_info *clki = NULL; + struct ice_clk_info *clki; struct device *dev = ice->pdev; struct list_head *head = &ice->clk_list_head; @@ -913,7 +918,7 @@ out: static int qcom_ice_enable_clocks(struct ice_device *ice, bool enable) { int ret = 0; - struct ice_clk_info *clki = NULL; + struct ice_clk_info *clki; struct device *dev = ice->pdev; struct list_head *head = &ice->clk_list_head; @@ -975,8 +980,7 @@ static int qcom_ice_secure_ice_init(struct ice_device *ice_dev) static int qcom_ice_update_sec_cfg(struct ice_device *ice_dev) { - int ret = 0; - u64 scm_ret = 0; + int ret = 0, scm_ret = 0; /* scm command buffer structure */ struct qcom_scm_cmd_buf { @@ -1002,7 +1006,7 @@ static int qcom_ice_update_sec_cfg(struct ice_device *ice_dev) cbuf.device_id = ICE_TZ_DEV_ID; ret = scm_restore_sec_cfg(cbuf.device_id, cbuf.spare, &scm_ret); if (ret || scm_ret) { - pr_err("%s: failed, ret %d scm_ret %llu\n", + pr_err("%s: failed, ret %d scm_ret %d\n", __func__, ret, scm_ret); if (!ret) ret = scm_ret; @@ -1590,14 +1594,12 @@ struct platform_device *qcom_ice_get_pdevice(struct device_node *node) if (ice_dev->pdev->of_node == node) { pr_info("%s: found ice device %pK\n", __func__, ice_dev); - ice_pdev = to_platform_device(ice_dev->pdev); break; } } - if (ice_pdev) - pr_info("%s: matching platform device %pK\n", __func__, - ice_pdev); + ice_pdev = to_platform_device(ice_dev->pdev); + pr_info("%s: matching platform device %pK\n", __func__, ice_pdev); out: return ice_pdev; } @@ -1617,11 +1619,11 @@ static struct ice_device *get_ice_device_from_storage_type if (!strcmp(ice_dev->ice_instance_type, storage_type)) { pr_debug("%s: found ice device %pK\n", __func__, ice_dev); - return ice_dev; + break; } } out: - return NULL; + return ice_dev; } static int enable_ice_setup(struct ice_device *ice_dev) diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index b44f926a6ba0376681c1cf86d3c960036a0ead79..4ab8ca143f6cf06904aaa17e61e7bfc886537f7b 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -2155,10 +2155,6 @@ static int _sha_complete(struct qce_device *pce_dev, int req_info) pce_sps_data = &preq_info->ce_sps; qce_callback = preq_info->qce_cb; areq = (struct ahash_request *) preq_info->areq; - if (!areq) { - pr_err("sha operation error. areq is NULL\n"); - return -ENXIO; - } qce_dma_unmap_sg(pce_dev->pdev, areq->src, preq_info->src_nents, DMA_TO_DEVICE); memcpy(digest, (char *)(&pce_sps_data->result->auth_iv[0]), @@ -2974,7 +2970,7 @@ static inline int qce_alloc_req_info(struct qce_device *pce_dev) request_index++; if (request_index >= MAX_QCE_BAM_REQ) request_index = 0; - if (atomic_xchg(&pce_dev->ce_request_info[request_index]. + if (xchg(&pce_dev->ce_request_info[request_index]. in_use, true) == false) { pce_dev->ce_request_index = request_index; return request_index; @@ -2990,8 +2986,7 @@ static inline void qce_free_req_info(struct qce_device *pce_dev, int req_info, bool is_complete) { pce_dev->ce_request_info[req_info].xfer_type = QCE_XFER_TYPE_LAST; - if (atomic_xchg(&pce_dev->ce_request_info[req_info].in_use, - false) == true) { + if (xchg(&pce_dev->ce_request_info[req_info].in_use, false) == true) { if (req_info < MAX_QCE_BAM_REQ && is_complete) atomic_dec(&pce_dev->no_of_queued_req); } else @@ -4615,7 +4610,7 @@ static int qce_dummy_req(struct qce_device *pce_dev) { int ret = 0; - if (!(atomic_xchg(&pce_dev->ce_request_info[DUMMY_REQ_INDEX]. + if (!(xchg(&pce_dev->ce_request_info[DUMMY_REQ_INDEX]. in_use, true) == false)) return -EBUSY; ret = qce_process_sha_req(pce_dev, NULL); @@ -5974,7 +5969,7 @@ void *qce_open(struct platform_device *pdev, int *rc) } for (i = 0; i < MAX_QCE_ALLOC_BAM_REQ; i++) - atomic_set(&pce_dev->ce_request_info[i].in_use, false); + pce_dev->ce_request_info[i].in_use = false; pce_dev->ce_request_index = 0; pce_dev->memsize = 10 * PAGE_SIZE * MAX_QCE_ALLOC_BAM_REQ; @@ -6138,13 +6133,12 @@ EXPORT_SYMBOL(qce_hw_support); void qce_dump_req(void *handle) { int i; - bool req_in_use; struct qce_device *pce_dev = (struct qce_device *)handle; for (i = 0; i < MAX_QCE_BAM_REQ; i++) { - req_in_use = atomic_read(&pce_dev->ce_request_info[i].in_use); - pr_info("qce_dump_req %d %d\n", i, req_in_use); - if (req_in_use == true) + pr_info("qce_dump_req %d %d\n", i, + pce_dev->ce_request_info[i].in_use); + if (pce_dev->ce_request_info[i].in_use == true) _qce_dump_descr_fifos(pce_dev, i); } } diff --git a/drivers/crypto/msm/qce50.h b/drivers/crypto/msm/qce50.h index ab0d21da72c5c8fa15f2e60ce3abcc29198fd059..6dba3664ff08abc91904799e43ef03a5f4cf4987 100644 --- a/drivers/crypto/msm/qce50.h +++ b/drivers/crypto/msm/qce50.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -214,7 +214,7 @@ struct ce_sps_data { }; struct ce_request_info { - atomic_t in_use; + bool in_use; bool in_prog; enum qce_xfer_type_enum xfer_type; struct ce_sps_data ce_sps; diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c index f38fc422b35ea1d72cf27785a9f80f0e3a657673..5b364f053b1b23e9a8121f57c45a759af74cdff6 100644 --- a/drivers/crypto/msm/qcrypto.c +++ b/drivers/crypto/msm/qcrypto.c @@ -3972,7 +3972,6 @@ static int _sha1_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int len) { struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base); - int ret = 0; memset(&sha_ctx->authkey[0], 0, SHA1_BLOCK_SIZE); if (len <= SHA1_BLOCK_SIZE) { memcpy(&sha_ctx->authkey[0], key, len); @@ -3980,19 +3979,16 @@ static int _sha1_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, } else { sha_ctx->alg = QCE_HASH_SHA1; sha_ctx->diglen = SHA1_DIGEST_SIZE; - ret = _sha_hmac_setkey(tfm, key, len); - if (ret) - pr_err("SHA1 hmac setkey failed\n"); + _sha_hmac_setkey(tfm, key, len); sha_ctx->authkey_in_len = SHA1_BLOCK_SIZE; } - return ret; + return 0; } static int _sha256_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int len) { struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base); - int ret = 0; memset(&sha_ctx->authkey[0], 0, SHA256_BLOCK_SIZE); if (len <= SHA256_BLOCK_SIZE) { @@ -4001,13 +3997,11 @@ static int _sha256_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, } else { sha_ctx->alg = QCE_HASH_SHA256; sha_ctx->diglen = SHA256_DIGEST_SIZE; - ret = _sha_hmac_setkey(tfm, key, len); - if (ret) - pr_err("SHA256 hmac setkey failed\n"); + _sha_hmac_setkey(tfm, key, len); sha_ctx->authkey_in_len = SHA256_BLOCK_SIZE; } - return ret; + return 0; } static int _sha_hmac_init_ihash(struct ahash_request *req, diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 6a60936b46e0e1f15ced9fc108ee983a61f385c5..9a8a18aafd5cb6eb577285c7a9cd1c4105f190b2 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -804,7 +804,7 @@ static void talitos_unregister_rng(struct device *dev) * crypto alg */ #define TALITOS_CRA_PRIORITY 3000 -#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE) +#define TALITOS_MAX_KEY_SIZE 96 #define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ struct talitos_ctx { @@ -1388,11 +1388,6 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, { struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); - if (keylen > TALITOS_MAX_KEY_SIZE) { - crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - memcpy(&ctx->key, key, keylen); ctx->keylen = keylen; diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c index f31089d63e0c1fd7aa3fbdbee6156cc003250bb7..b6ac7160da57fe68a2341f5237b83705fd35d491 100644 --- a/drivers/devfreq/governor_msm_adreno_tz.c +++ b/drivers/devfreq/governor_msm_adreno_tz.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -26,6 +31,7 @@ static DEFINE_SPINLOCK(tz_lock); static DEFINE_SPINLOCK(sample_lock); +static DEFINE_SPINLOCK(sample_load_lock); static DEFINE_SPINLOCK(suspend_lock); /* * FLOOR is 5msec to capture up to 3 re-draws @@ -58,9 +64,26 @@ static DEFINE_SPINLOCK(suspend_lock); #define TAG "msm_adreno_tz: " +#define USEC_PER_MINUTE (1*60*1000*1000) +#define NMAX (15*60*60+1) + +struct gpu_load_data { + unsigned long total_time; + unsigned long busy_time; + u64 update_time; +}; + +struct gpu_load_queue { + struct gpu_load_data *gpu_load; + int head; + int tail; +}; + static u64 suspend_time; static u64 suspend_start; static unsigned long acc_total, acc_relative_busy; +static unsigned long gpu_load_total, gpu_load_rel_busy; +static struct gpu_load_queue *gpu_load_infos; static struct msm_adreno_extended_profile *partner_gpu_profile; static void do_partner_start_event(struct work_struct *work); @@ -109,6 +132,123 @@ static ssize_t gpu_load_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%lu\n", sysfs_busy_perc); } +int findItem(int head, int tail, u64 refTime) +{ + int low = head, high = tail, middle; + u64 update_time; + + while (low < high) { + middle = (low + high) / 2; + update_time = + gpu_load_infos->gpu_load[middle % NMAX].update_time; + + if (update_time <= refTime) + low = middle + 1; + else if (update_time > refTime) + high = middle - 1; + } + + update_time = gpu_load_infos->gpu_load[low % NMAX].update_time; + if (update_time > refTime) + low = low - 1; + + if (low < tail) { + u64 l = gpu_load_infos->gpu_load[low % NMAX].update_time; + u64 r = gpu_load_infos->gpu_load[(low+1) % NMAX].update_time; + + if (r - refTime < refTime - l) + low = low + 1; + } + return low % NMAX; +} + +unsigned long cal_gpu_load(u64 current_time, u64 update_time, + u64 begin_time, int minutes) +{ + unsigned long sysfs_busy_perc; + unsigned long tmp_act_relative_busy, tmp_act_total; + int tail = gpu_load_infos->tail, head = gpu_load_infos->head; + + if (current_time - update_time > minutes * USEC_PER_MINUTE) { + sysfs_busy_perc = 0; + } else { + int tmpIndex = head; + + if (current_time - begin_time <= minutes * USEC_PER_MINUTE) { + tmpIndex = head; + } else { + u64 begin = current_time - minutes * USEC_PER_MINUTE; + int tmpTail = (tail < head) ? tail + NMAX : tail; + + tmpIndex = findItem(head, tmpTail-1, begin); + } + + tmp_act_relative_busy = + gpu_load_infos->gpu_load[tail-1].busy_time - + gpu_load_infos->gpu_load[tmpIndex].busy_time; + + tmp_act_total = current_time - + gpu_load_infos->gpu_load[tmpIndex].update_time; + + sysfs_busy_perc = (tmp_act_relative_busy * 100 * 10) / + tmp_act_total; + } + return sysfs_busy_perc; +} + +void convert_int_to_string(unsigned long perc, char *str, unsigned int size) +{ + char low[6] = "0"; + char mid[] = "."; + + snprintf(str, sizeof(low), "%lu", (perc / 10)); + snprintf(low, sizeof(low), "%lu", (perc % 10)); + strlcat(str, mid, size); + strlcat(str, low, size); +} + +static ssize_t gpu_period_load_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned long sysfs_busy_perc[3]; + int tail, head; + char load[3][6] = {"0", "0", "0"}; + int i; + unsigned int size; + spin_lock(&sample_load_lock); + tail = gpu_load_infos->tail; + head = gpu_load_infos->head; + + if (tail == head) { + sysfs_busy_perc[0] = 0; + sysfs_busy_perc[1] = 0; + sysfs_busy_perc[2] = 0; + } else { + u64 current_time = (u64)ktime_to_us(ktime_get()); + u64 update_time = gpu_load_infos->gpu_load[tail-1].update_time; + u64 begin_time = gpu_load_infos->gpu_load[head].update_time; + + sysfs_busy_perc[0] = cal_gpu_load(current_time, + update_time, begin_time, 1); + sysfs_busy_perc[1] = cal_gpu_load(current_time, + update_time, begin_time, 5); + sysfs_busy_perc[2] = cal_gpu_load(current_time, + update_time, begin_time, 15); + } + for (i = 0; i < 3; i++) { + size = sizeof(load[i]); + convert_int_to_string(sysfs_busy_perc[i], load[i], size); + } + + spin_unlock(&sample_load_lock); + return snprintf(buf, PAGE_SIZE, "%s %s %s\n", + load[0], + load[1], + load[2] + ); +} + /* * Returns the time in ms for which gpu was in suspend state * since last time the entry is read. @@ -135,6 +275,7 @@ static ssize_t suspend_time_show(struct device *dev, } static DEVICE_ATTR(gpu_load, 0444, gpu_load_show, NULL); +static DEVICE_ATTR(gpu_period_load, 0444, gpu_period_load_show, NULL); static DEVICE_ATTR(suspend_time, 0444, suspend_time_show, @@ -142,10 +283,28 @@ static DEVICE_ATTR(suspend_time, 0444, static const struct device_attribute *adreno_tz_attr_list[] = { &dev_attr_gpu_load, + &dev_attr_gpu_period_load, &dev_attr_suspend_time, NULL }; +void store_work_load(unsigned long gpu_load_total, unsigned long gpu_load_busy) +{ + /* Queue item to gpu_load_queue */ + int index = gpu_load_infos->tail; + int head = gpu_load_infos->head; + + gpu_load_infos->gpu_load[index].total_time = gpu_load_total; + gpu_load_infos->gpu_load[index].busy_time = gpu_load_busy; + gpu_load_infos->gpu_load[index].update_time = + (u64)ktime_to_us(ktime_get()); + + if ((index + 1) % NMAX == head) + gpu_load_infos->head = (head + 1) % NMAX; + + gpu_load_infos->tail = (index + 1) % NMAX; +} + void compute_work_load(struct devfreq_dev_status *stats, struct devfreq_msm_adreno_tz_data *priv, struct devfreq *devfreq) @@ -160,6 +319,15 @@ void compute_work_load(struct devfreq_dev_status *stats, acc_relative_busy += (stats->busy_time * stats->current_frequency) / devfreq->profile->freq_table[0]; spin_unlock(&sample_lock); + + spin_lock(&sample_load_lock); + gpu_load_total += stats->total_time; + gpu_load_rel_busy += (stats->busy_time * stats->current_frequency) / + devfreq->profile->freq_table[0]; + + store_work_load(gpu_load_total, gpu_load_rel_busy); + + spin_unlock(&sample_load_lock); } /* Trap into the TrustZone, and call funcs there. */ @@ -230,6 +398,14 @@ static int __secure_tz_update_entry3(unsigned int *scm_data, u32 size_scm_data, return ret; } +static void tz_init_gpuloadinfos(void) +{ + gpu_load_infos = kzalloc(sizeof(struct gpu_load_queue), GFP_KERNEL); + gpu_load_infos->head = gpu_load_infos->tail = 0; + gpu_load_infos->gpu_load = + kcalloc(NMAX, sizeof(struct gpu_load_data), GFP_KERNEL); +} + static int tz_init_ca(struct devfreq_msm_adreno_tz_data *priv) { unsigned int tz_ca_data[2]; @@ -269,6 +445,8 @@ static int tz_init(struct devfreq_msm_adreno_tz_data *priv, unsigned int *version, u32 size_version) { int ret; + + tz_init_gpuloadinfos(); /* Make sure all CMD IDs are avaialble */ if (scm_is_call_available(SCM_SVC_DCVS, TZ_INIT_ID)) { ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID, tz_pwrlevels, diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index 6eab3ea187c6925b5612ae29dc5b8f343ae32e8d..26f69fa61ba12cd575fe8555fe3daf8dcb36e313 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -88,10 +88,12 @@ static void mdm_enable_irqs(struct mdm_ctrl *mdm) return; if (mdm->irq_mask & IRQ_ERRFATAL) { enable_irq(mdm->errfatal_irq); + irq_set_irq_wake(mdm->errfatal_irq, 1); mdm->irq_mask &= ~IRQ_ERRFATAL; } if (mdm->irq_mask & IRQ_STATUS) { enable_irq(mdm->status_irq); + irq_set_irq_wake(mdm->status_irq, 1); mdm->irq_mask &= ~IRQ_STATUS; } if (mdm->irq_mask & IRQ_PBLRDY) { @@ -105,10 +107,12 @@ static void mdm_disable_irqs(struct mdm_ctrl *mdm) if (!mdm) return; if (!(mdm->irq_mask & IRQ_ERRFATAL)) { + irq_set_irq_wake(mdm->errfatal_irq, 0); disable_irq_nosync(mdm->errfatal_irq); mdm->irq_mask |= IRQ_ERRFATAL; } if (!(mdm->irq_mask & IRQ_STATUS)) { + irq_set_irq_wake(mdm->status_irq, 0); disable_irq_nosync(mdm->status_irq); mdm->irq_mask |= IRQ_STATUS; } @@ -697,7 +701,6 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev) goto errfatal_err; } mdm->errfatal_irq = irq; - irq_set_irq_wake(mdm->errfatal_irq, 1); errfatal_err: /* status irq */ @@ -716,7 +719,6 @@ errfatal_err: goto status_err; } mdm->status_irq = irq; - irq_set_irq_wake(mdm->status_irq, 1); status_err: if (gpio_is_valid(MDM_GPIO(mdm, MDM2AP_PBLRDY))) { irq = platform_get_irq_byname(pdev, "plbrdy_irq"); diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index db8f0eeca7c9e0e5c3be66c8b6358fb666c71492..15c362a2be1c51213d097ae552ba2ecdf273f239 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -23,6 +23,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -80,6 +85,8 @@ static const char *extcon_name[] = { [EXTCON_JIG] = "JIG", [EXTCON_MECHANICAL] = "MECHANICAL", + /* Somc Extention */ + [EXTCON_VBUS_DROP] = "VBUS-DROP", NULL, }; diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index c893681f3bf3341b45cdfbb66e9d709419b229bc..4a3afc00f827432c55f793c0404d35dbce302e31 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -26,6 +31,11 @@ #include #include +#include + +#ifdef CONFIG_LAST_LOGS +#include +#endif /* QSEE_LOG_BUF_SIZE = 32K */ #define QSEE_LOG_BUF_SIZE 0x8000 @@ -1165,6 +1175,150 @@ err: return -ENXIO; } +#ifdef CONFIG_LAST_LOGS +#define TZBSP_DIAG_MAGIC 0x747a6461 +#define MAX_BANNER_LEN 1024 +#define TZDBG_STATS_COUNT (TZDBG_LOG + 1) +static int (*disp_stat[TZDBG_STATS_MAX])(void); +static char *merge_buf; +static uint32_t merge_buf_len; + +static int _tz_log_stats(void) +{ + 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)); + + /* No data in ring buffer, so no need to hang around */ + if (log_ptr && log_ptr->log_pos.offset == 0 && log_ptr->log_pos.wrap == 0) + return 0; + + return _disp_log_stats(log_ptr, &log_start, + tzdbg.diag_buf->ring_len, debug_rw_buf_size, TZDBG_LOG); +} + +static void merge_buffers(void) +{ + int data_len = 0, len = 0, i, status = SECURITY_ON; + + if (get_security_status(&status) < 0) + pr_warn("Unable to get security status.\n"); + + for (i = 0; i < TZDBG_STATS_COUNT; i++) { + if ((status == SECURITY_ON) && (i == TZDBG_LOG)) + continue; + + if ((len + MAX_BANNER_LEN + debug_rw_buf_size) < + merge_buf_len) { + len += snprintf(merge_buf + len, + MAX_BANNER_LEN, "\n\n--------%s--------\n\n", + tzdbg.stat[i].name); + data_len = disp_stat[i](); + memcpy(merge_buf + len, tzdbg.stat[i].data, data_len); + len += data_len; + memset(tzdbg.disp_buf, 0x0, debug_rw_buf_size); + } + } + + merge_buf_len = len; + pr_info("Length of merged buffers %d\n", len); +} + +int format_tzbsp_log(void *src, size_t src_sz, void **dst, uint32_t *dst_sz) +{ + char *save_disp_buf_addr = NULL; + uint32_t save_debug_rw_buf_size = 0; + struct tzdbg_t *dbg = (struct tzdbg_t *)src; + int ret = 0; + + if (debug_rw_buf_size != src_sz) + pr_warn("%s: Diag buffer size does not match - 0x%lx", + __func__, src_sz); + + if (dbg == NULL || !src_sz || !tzdbg.diag_buf) + return -EINVAL; + + /* validate tzdiag area w.r.t magic */ + if (dbg->magic_num != TZBSP_DIAG_MAGIC) { + pr_err("No magic found, magic: 0x%x\n", dbg->magic_num); + return -ENXIO; + } + + /* As we use the tzdbg.disp_buf pointer, backup tzdbg.disp_buf and + restore it before returns */ + save_disp_buf_addr = tzdbg.disp_buf; + save_debug_rw_buf_size = debug_rw_buf_size; + + /* Debug buffer size increased to 48k (12K*4) size. + Because, formatted output buffer size is more than the + unformatted buffer size */ + /* debug_rw_buf_size is modified and will be restored + before the function returns*/ + debug_rw_buf_size = src_sz * 4; + + /* Merge buffer increased to 294k size */ + merge_buf_len = (debug_rw_buf_size + MAX_BANNER_LEN) * + TZDBG_STATS_COUNT; + + merge_buf = kzalloc(merge_buf_len, GFP_KERNEL); + if (merge_buf == NULL) { + pr_err("%s: Can't Allocate memory: merged_buf\n", + __func__); + ret = -ENOMEM; + goto exit; + } + + tzdbg.disp_buf = kzalloc(debug_rw_buf_size, GFP_KERNEL); + if (tzdbg.disp_buf == NULL) { + pr_err("%s: Can't Allocate memory: disp_buf\n", + __func__); + ret = -ENOMEM; + goto exit1; + } + + memcpy(tzdbg.diag_buf, src, src_sz); + + disp_stat[TZDBG_BOOT] = _disp_tz_boot_stats; + disp_stat[TZDBG_RESET] = _disp_tz_reset_stats; + disp_stat[TZDBG_INTERRUPT] = _disp_tz_interrupt_stats; + disp_stat[TZDBG_VMID] = _disp_tz_vmid_stats; + disp_stat[TZDBG_GENERAL] = _disp_tz_general_stats; + if (TZBSP_DIAG_MAJOR_VERSION_LEGACY < + (tzdbg.diag_buf->version >> 16)) { + disp_stat[TZDBG_LOG] = _tz_log_stats; + } else { + disp_stat[TZDBG_LOG] = _disp_tz_log_stats_legacy; + } + + merge_buffers(); + /* Allocate required buffer to store the formatted logs */ + *dst = kzalloc(merge_buf_len, GFP_KERNEL); + if (*dst == NULL) { + pr_err("%s: Can't Allocate memory: buffer\n", + __func__); + ret = -ENOMEM; + goto exit2; + } + + *dst_sz = merge_buf_len; + memcpy(*dst, merge_buf, *dst_sz); + +exit2: + memset(tzdbg.diag_buf, 0x0, src_sz); + kzfree(tzdbg.disp_buf); +exit1: + kzfree(merge_buf); +exit: + /* Restore tzdbg.disp_buf pointer and debug_rw_buf_size */ + tzdbg.disp_buf = save_disp_buf_addr; + debug_rw_buf_size = save_debug_rw_buf_size; + return ret; +} + +#endif static int tz_log_remove(struct platform_device *pdev) { diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 06d345b087f878a67d2352b85ddb7454e2c6167b..0d93ed3f485f3769ed9d54b8c1e336cdda0401d4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c index 62cd78a953031621148ec90bde2871d543275e55..542ebdd9386895092c96d8c9423db16099d8f006 100644 --- a/drivers/gpio/qpnp-pin.c +++ b/drivers/gpio/qpnp-pin.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -718,6 +723,117 @@ gpio_cfg: return rc; } +static int _qpnp_get_pin_config(struct qpnp_pin_chip *q_chip, + struct qpnp_pin_spec *q_spec, struct qpnp_pin_cfg *param) +{ + u8 shift, mask, *reg; + + if (is_gpio_lv_mv(q_spec)) { + shift = Q_REG_LV_MV_MODE_SEL_SHIFT; + mask = Q_REG_LV_MV_MODE_SEL_MASK; + } else { + shift = Q_REG_MODE_SEL_SHIFT; + mask = Q_REG_MODE_SEL_MASK; + } + param->mode = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL], + shift, mask); + + param->output_type = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL], + Q_REG_OUT_TYPE_SHIFT, + Q_REG_OUT_TYPE_MASK); + + if (is_gpio_lv_mv(q_spec)) { + shift = Q_REG_DIG_OUT_SRC_INVERT_SHIFT; + mask = Q_REG_DIG_OUT_SRC_INVERT_MASK; + reg = &q_spec->regs[Q_REG_I_DIG_OUT_SRC_CTL]; + } else { + shift = Q_REG_OUT_INVERT_SHIFT; + mask = Q_REG_OUT_INVERT_MASK; + reg = &q_spec->regs[Q_REG_I_MODE_CTL]; + } + param->invert = q_reg_get(reg, shift, mask); + + param->pull = q_reg_get(&q_spec->regs[Q_REG_I_DIG_PULL_CTL], + Q_REG_PULL_SHIFT, Q_REG_PULL_MASK); + param->vin_sel = q_reg_get(&q_spec->regs[Q_REG_I_DIG_VIN_CTL], + Q_REG_VIN_SHIFT, Q_REG_VIN_MASK); + param->out_strength = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL], + Q_REG_OUT_STRENGTH_SHIFT, + Q_REG_OUT_STRENGTH_MASK); + + if (is_gpio_lv_mv(q_spec)) { + shift = Q_REG_DIG_OUT_SRC_SRC_SEL_SHIFT; + mask = Q_REG_DIG_OUT_SRC_SRC_SEL_MASK; + reg = &q_spec->regs[Q_REG_I_DIG_OUT_SRC_CTL]; + } else { + shift = Q_REG_SRC_SEL_SHIFT; + mask = Q_REG_SRC_SEL_MASK; + reg = &q_spec->regs[Q_REG_I_MODE_CTL]; + } + param->src_sel = q_reg_get(reg, shift, mask); + + param->master_en = q_reg_get(&q_spec->regs[Q_REG_I_EN_CTL], + Q_REG_MASTER_EN_SHIFT, + Q_REG_MASTER_EN_MASK); + param->aout_ref = q_reg_get(&q_spec->regs[Q_REG_I_AOUT_CTL], + Q_REG_AOUT_REF_SHIFT, + Q_REG_AOUT_REF_MASK); + param->ain_route = q_reg_get(&q_spec->regs[Q_REG_I_AIN_CTL], + Q_REG_AIN_ROUTE_SHIFT, + Q_REG_AIN_ROUTE_MASK); + param->cs_out = q_reg_get(&q_spec->regs[Q_REG_I_SINK_CTL], + Q_REG_CS_OUT_SHIFT, + Q_REG_CS_OUT_MASK); + param->apass_sel = q_reg_get(&q_spec->regs[Q_REG_I_APASS_SEL_CTL], + Q_REG_APASS_SEL_SHIFT, + Q_REG_APASS_SEL_MASK); + if (is_gpio_lv_mv(q_spec)) { + param->dtest_sel = q_reg_get(&q_spec->regs[Q_REG_I_DIG_IN_CTL], + Q_REG_LV_MV_DTEST_SEL_CFG_SHIFT, + Q_REG_LV_MV_DTEST_SEL_CFG_MASK); + } else { + param->dtest_sel = q_reg_get(&q_spec->regs[Q_REG_I_DIG_IN_CTL], + Q_REG_DTEST_SEL_SHIFT, + Q_REG_DTEST_SEL_MASK); + } + return 0; +} + +int qpnp_get_pin_config(int gpio, struct qpnp_pin_cfg *param) +{ + int rc, chip_offset; + struct qpnp_pin_chip *q_chip; + struct qpnp_pin_spec *q_spec = NULL; + struct gpio_chip *gpio_chip; + + if (param == NULL) + return -EINVAL; + + mutex_lock(&qpnp_pin_chips_lock); + list_for_each_entry(q_chip, &qpnp_pin_chips, chip_list) { + gpio_chip = &q_chip->gpio_chip; + if (gpio >= gpio_chip->base + && gpio < gpio_chip->base + gpio_chip->ngpio) { + chip_offset = gpio - gpio_chip->base; + q_spec = qpnp_chip_gpio_get_spec(q_chip, chip_offset); + if (WARN_ON(!q_spec)) { + mutex_unlock(&qpnp_pin_chips_lock); + return -ENODEV; + } + break; + } + } + mutex_unlock(&qpnp_pin_chips_lock); + + if (!q_spec) + return -ENODEV; + + rc = _qpnp_get_pin_config(q_chip, q_spec, param); + + return rc; +} +EXPORT_SYMBOL(qpnp_get_pin_config); + int qpnp_pin_config(int gpio, struct qpnp_pin_cfg *param) { int rc, chip_offset; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index f4cae5357e400cd0a8b1338e955a6c3b9cf20eef..51a9942cdb40f48044b85e98fef482b20bf9d6b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -681,10 +681,6 @@ int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev) DRM_INFO("Changing default dispclk from %dMhz to 600Mhz\n", adev->clock.default_dispclk / 100); adev->clock.default_dispclk = 60000; - } else if (adev->clock.default_dispclk <= 60000) { - DRM_INFO("Changing default dispclk from %dMhz to 625Mhz\n", - adev->clock.default_dispclk / 100); - adev->clock.default_dispclk = 62500; } adev->clock.dp_extclk = le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 2bc17a907ecf59e38a48d60d9c8a77bba1941239..25a3e2485cc2e9572943638d1975f678fbc26e38 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -124,13 +124,6 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type, } break; } - - if (!(*out_ring && (*out_ring)->adev)) { - DRM_ERROR("Ring %d is not initialized on IP %d\n", - ring, ip_type); - return -EINVAL; - } - return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c index 247b088990dc7d54344b16e0670ff37c8dbfeeb6..49aa350166534f161288322b1ad04241d4ac6ba8 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c @@ -164,7 +164,7 @@ void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state) struct drm_device *dev = crtc->dev; struct amdgpu_device *adev = dev->dev_private; int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); - ENABLE_DISP_POWER_GATING_PS_ALLOCATION args; + ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args; memset(&args, 0, sizeof(args)); @@ -177,7 +177,7 @@ void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state) void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev) { int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); - ENABLE_DISP_POWER_GATING_PS_ALLOCATION args; + ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args; memset(&args, 0, sizeof(args)); diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index b5c64edeb668a9ec41e404b10c4960fdb2100495..b92139e9b9d8f5e08ae19ce5b75607ceab845104 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -113,11 +113,7 @@ struct ast_private { struct ttm_bo_kmap_obj cache_kmap; int next_cursor; bool support_wide_screen; - enum { - ast_use_p2a, - ast_use_dt, - ast_use_defaults - } config_mode; + bool DisableP2A; enum ast_tx_chip tx_chip_type; u8 dp501_maxclk; diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 498a94069e6b2f037b7821dc373413be8a0e1d2d..6c021165ca67a5a727effa53255153a3d35b8a21 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -62,84 +62,13 @@ uint8_t ast_get_index_reg_mask(struct ast_private *ast, return ret; } -static void ast_detect_config_mode(struct drm_device *dev, u32 *scu_rev) -{ - struct device_node *np = dev->pdev->dev.of_node; - struct ast_private *ast = dev->dev_private; - uint32_t data, jregd0, jregd1; - - /* Defaults */ - ast->config_mode = ast_use_defaults; - *scu_rev = 0xffffffff; - - /* Check if we have device-tree properties */ - if (np && !of_property_read_u32(np, "aspeed,scu-revision-id", - scu_rev)) { - /* We do, disable P2A access */ - ast->config_mode = ast_use_dt; - DRM_INFO("Using device-tree for configuration\n"); - return; - } - - /* Not all families have a P2A bridge */ - if (dev->pdev->device != PCI_CHIP_AST2000) - return; - - /* - * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge - * is disabled. We force using P2A if VGA only mode bit - * is set D[7] - */ - jregd0 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); - jregd1 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff); - if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) { - /* Double check it's actually working */ - data = ast_read32(ast, 0xf004); - if (data != 0xFFFFFFFF) { - /* P2A works, grab silicon revision */ - ast->config_mode = ast_use_p2a; - - DRM_INFO("Using P2A bridge for configuration\n"); - - /* Read SCU7c (silicon revision register) */ - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - *scu_rev = ast_read32(ast, 0x1207c); - return; - } - } - - /* We have a P2A bridge but it's disabled */ - DRM_INFO("P2A bridge disabled, using default configuration\n"); -} static int ast_detect_chip(struct drm_device *dev, bool *need_post) { struct ast_private *ast = dev->dev_private; - uint32_t jreg, scu_rev; - - /* - * If VGA isn't enabled, we need to enable now or subsequent - * access to the scratch registers will fail. We also inform - * our caller that it needs to POST the chip - * (Assumption: VGA not enabled -> need to POST) - */ - if (!ast_is_vga_enabled(dev)) { - ast_enable_vga(dev); - DRM_INFO("VGA not enabled on entry, requesting chip POST\n"); - *need_post = true; - } else - *need_post = false; - - - /* Enable extended register access */ - ast_enable_mmio(dev); + uint32_t data, jreg; ast_open_key(ast); - /* Find out whether P2A works or whether to use device-tree */ - ast_detect_config_mode(dev, &scu_rev); - - /* Identify chipset */ if (dev->pdev->device == PCI_CHIP_AST1180) { ast->chip = AST1100; DRM_INFO("AST 1180 detected\n"); @@ -151,7 +80,12 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) ast->chip = AST2300; DRM_INFO("AST 2300 detected\n"); } else if (dev->pdev->revision >= 0x10) { - switch (scu_rev & 0x0300) { + uint32_t data; + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + + data = ast_read32(ast, 0x1207c); + switch (data & 0x0300) { case 0x0200: ast->chip = AST1100; DRM_INFO("AST 1100 detected\n"); @@ -176,6 +110,26 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) } } + /* + * If VGA isn't enabled, we need to enable now or subsequent + * access to the scratch registers will fail. We also inform + * our caller that it needs to POST the chip + * (Assumption: VGA not enabled -> need to POST) + */ + if (!ast_is_vga_enabled(dev)) { + ast_enable_vga(dev); + ast_enable_mmio(dev); + DRM_INFO("VGA not enabled on entry, requesting chip POST\n"); + *need_post = true; + } else + *need_post = false; + + /* Check P2A Access */ + ast->DisableP2A = true; + data = ast_read32(ast, 0xf004); + if (data != 0xFFFFFFFF) + ast->DisableP2A = false; + /* Check if we support wide screen */ switch (ast->chip) { case AST1180: @@ -192,12 +146,17 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) ast->support_wide_screen = true; else { ast->support_wide_screen = false; - if (ast->chip == AST2300 && - (scu_rev & 0x300) == 0x0) /* ast1300 */ - ast->support_wide_screen = true; - if (ast->chip == AST2400 && - (scu_rev & 0x300) == 0x100) /* ast1400 */ - ast->support_wide_screen = true; + if (ast->DisableP2A == false) { + /* Read SCU7c (silicon revision register) */ + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + data = ast_read32(ast, 0x1207c); + data &= 0x300; + if (ast->chip == AST2300 && data == 0x0) /* ast1300 */ + ast->support_wide_screen = true; + if (ast->chip == AST2400 && data == 0x100) /* ast1400 */ + ast->support_wide_screen = true; + } } break; } @@ -261,102 +220,85 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) static int ast_get_dram_info(struct drm_device *dev) { - struct device_node *np = dev->pdev->dev.of_node; struct ast_private *ast = dev->dev_private; - uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap; - uint32_t denum, num, div, ref_pll, dsel; + uint32_t data, data2; + uint32_t denum, num, div, ref_pll; - switch (ast->config_mode) { - case ast_use_dt: - /* - * If some properties are missing, use reasonable - * defaults for AST2400 - */ - if (of_property_read_u32(np, "aspeed,mcr-configuration", - &mcr_cfg)) - mcr_cfg = 0x00000577; - if (of_property_read_u32(np, "aspeed,mcr-scu-mpll", - &mcr_scu_mpll)) - mcr_scu_mpll = 0x000050C0; - if (of_property_read_u32(np, "aspeed,mcr-scu-strap", - &mcr_scu_strap)) - mcr_scu_strap = 0; - break; - case ast_use_p2a: - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - mcr_cfg = ast_read32(ast, 0x10004); - mcr_scu_mpll = ast_read32(ast, 0x10120); - mcr_scu_strap = ast_read32(ast, 0x10170); - break; - case ast_use_defaults: - default: + if (ast->DisableP2A) + { ast->dram_bus_width = 16; ast->dram_type = AST_DRAM_1Gx16; ast->mclk = 396; - return 0; } - - if (mcr_cfg & 0x40) - ast->dram_bus_width = 16; else - ast->dram_bus_width = 32; + { + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + data = ast_read32(ast, 0x10004); - if (ast->chip == AST2300 || ast->chip == AST2400) { - switch (mcr_cfg & 0x03) { - case 0: - ast->dram_type = AST_DRAM_512Mx16; - break; - default: - case 1: - ast->dram_type = AST_DRAM_1Gx16; - break; - case 2: - ast->dram_type = AST_DRAM_2Gx16; - break; - case 3: - ast->dram_type = AST_DRAM_4Gx16; - break; + if (data & 0x40) + ast->dram_bus_width = 16; + else + ast->dram_bus_width = 32; + + if (ast->chip == AST2300 || ast->chip == AST2400) { + switch (data & 0x03) { + case 0: + ast->dram_type = AST_DRAM_512Mx16; + break; + default: + case 1: + ast->dram_type = AST_DRAM_1Gx16; + break; + case 2: + ast->dram_type = AST_DRAM_2Gx16; + break; + case 3: + ast->dram_type = AST_DRAM_4Gx16; + break; + } + } else { + switch (data & 0x0c) { + case 0: + case 4: + ast->dram_type = AST_DRAM_512Mx16; + break; + case 8: + if (data & 0x40) + ast->dram_type = AST_DRAM_1Gx16; + else + ast->dram_type = AST_DRAM_512Mx32; + break; + case 0xc: + ast->dram_type = AST_DRAM_1Gx32; + break; + } } - } else { - switch (mcr_cfg & 0x0c) { - case 0: - case 4: - ast->dram_type = AST_DRAM_512Mx16; + + data = ast_read32(ast, 0x10120); + data2 = ast_read32(ast, 0x10170); + if (data2 & 0x2000) + ref_pll = 14318; + else + ref_pll = 12000; + + denum = data & 0x1f; + num = (data & 0x3fe0) >> 5; + data = (data & 0xc000) >> 14; + switch (data) { + case 3: + div = 0x4; break; - case 8: - if (mcr_cfg & 0x40) - ast->dram_type = AST_DRAM_1Gx16; - else - ast->dram_type = AST_DRAM_512Mx32; + case 2: + case 1: + div = 0x2; break; - case 0xc: - ast->dram_type = AST_DRAM_1Gx32; + default: + div = 0x1; break; } + ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000); } - - if (mcr_scu_strap & 0x2000) - ref_pll = 14318; - else - ref_pll = 12000; - - denum = mcr_scu_mpll & 0x1f; - num = (mcr_scu_mpll & 0x3fe0) >> 5; - dsel = (mcr_scu_mpll & 0xc000) >> 14; - switch (dsel) { - case 3: - div = 0x4; - break; - case 2: - case 1: - div = 0x2; - break; - default: - div = 0x1; - break; - } - ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000); return 0; } diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index c7c58becb25d70169c26b5dfcd5f6f45b3d20574..270e8fb2803f7e671ae2cd09560535667c20923b 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -375,14 +375,17 @@ void ast_post_gpu(struct drm_device *dev) ast_enable_mmio(dev); ast_set_def_ext_reg(dev); - if (ast->config_mode == ast_use_p2a) { + if (ast->DisableP2A == false) + { if (ast->chip == AST2300 || ast->chip == AST2400) ast_init_dram_2300(dev); else ast_init_dram_reg(dev); ast_init_3rdtx(dev); - } else { + } + else + { if (ast->tx_chip_type != AST_TX_NONE) ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80); /* Enable DVO */ } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 47c1747e7ae3414eb3459954beea52bec738b06a..39b8e171cad564bf29e05558389a4710bc5651d0 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2716,7 +2716,6 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, #define VENDOR_BLOCK 0x03 #define SPEAKER_BLOCK 0x04 #define HDR_STATIC_METADATA_EXTENDED_DATA_BLOCK 0x06 -#define COLORIMETRY_EXTENDED_DATA_BLOCK 0x05 #define EXTENDED_TAG 0x07 #define VIDEO_CAPABILITY_BLOCK 0x07 #define Y420_VIDEO_DATA_BLOCK 0x0E @@ -3527,17 +3526,11 @@ drm_extract_vcdb_info(struct drm_connector *connector, const u8 *db) (db[2] & (BIT(3) | BIT(2))) >> 2; connector->ce_scan_info = db[2] & (BIT(1) | BIT(0)); - connector->rgb_qs = - db[2] & BIT(6); - connector->yuv_qs = - db[2] & BIT(7); DRM_DEBUG_KMS("Scan Info (pt|it|ce): (%d|%d|%d)", (int) connector->pt_scan_info, (int) connector->it_scan_info, (int) connector->ce_scan_info); - DRM_DEBUG_KMS("rgb_quant_range_select %d", connector->rgb_qs); - DRM_DEBUG_KMS("ycc_quant_range_select %d", connector->yuv_qs); } static bool drm_edid_is_luminance_value_present( @@ -3595,50 +3588,6 @@ drm_extract_hdr_db(struct drm_connector *connector, const u8 *db) DRM_DEBUG_KMS("min luminance %d\n", connector->hdr_min_luminance); } -/* - * drm_extract_colorimetry_db - Parse the HDMI colorimetry extended block - * @connector: connector corresponding to the HDMI sink - * @db: start of the HDMI colorimetry extended block - * - * Parses the HDMI colorimetry block to extract sink info for @connector. - */ -static void -drm_extract_clrmetry_db(struct drm_connector *connector, const u8 *db) -{ - - if (!db) { - DRM_ERROR("invalid db\n"); - return; - } - - /* Bit 0: xvYCC_601 */ - if (db[2] & BIT(0)) - connector->color_enc_fmt |= DRM_EDID_COLORIMETRY_xvYCC_601; - /* Bit 0: xvYCC_709 */ - if (db[2] & BIT(1)) - connector->color_enc_fmt |= DRM_EDID_COLORIMETRY_xvYCC_709; - /* Bit 0: sYCC_601 */ - if (db[2] & BIT(2)) - connector->color_enc_fmt |= DRM_EDID_COLORIMETRY_sYCC_601; - /* Bit 0: ADBYCC_601 */ - if (db[2] & BIT(3)) - connector->color_enc_fmt |= DRM_EDID_COLORIMETRY_ADBYCC_601; - /* Bit 0: ADB_RGB */ - if (db[2] & BIT(4)) - connector->color_enc_fmt |= DRM_EDID_COLORIMETRY_ADB_RGB; - /* Bit 0: BT2020_CYCC */ - if (db[2] & BIT(5)) - connector->color_enc_fmt |= DRM_EDID_COLORIMETRY_BT2020_CYCC; - /* Bit 0: BT2020_YCC */ - if (db[2] & BIT(6)) - connector->color_enc_fmt |= DRM_EDID_COLORIMETRY_BT2020_YCC; - /* Bit 0: BT2020_RGB */ - if (db[2] & BIT(7)) - connector->color_enc_fmt |= DRM_EDID_COLORIMETRY_BT2020_RGB; - - DRM_DEBUG_KMS("colorimetry fmt 0x%x\n", connector->color_enc_fmt); -} - /* * drm_hdmi_extract_extended_blk_info - Parse the HDMI extended tag blocks * @connector: connector corresponding to the HDMI sink @@ -3671,9 +3620,6 @@ struct edid *edid) case HDR_STATIC_METADATA_EXTENDED_DATA_BLOCK: drm_extract_hdr_db(connector, db); break; - case COLORIMETRY_EXTENDED_DATA_BLOCK: - drm_extract_clrmetry_db(connector, db); - break; default: break; } diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 4c082fff2fc5f73696fb5167d88bb82d5f0d615f..84125b3d1f955ecff08e5521e8509f9fc8a23112 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -48,7 +48,6 @@ msm_drm-y := \ sde/sde_backlight.o \ sde/sde_color_processing.o \ sde/sde_vbif.o \ - sde/sde_splash.o \ sde_dbg_evtlog.o \ sde_io_util.o \ dba_bridge.o \ diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index c085e173232b8f115ce3375407db512a8038bb49..e24827590b7c6cb1fb14c345fa23c263eb4a69fd 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -409,8 +409,8 @@ static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) gpu->funcs->pm_resume(gpu); seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A3XX_RBBM_STATUS)); - adreno_show(gpu, m); gpu->funcs->pm_suspend(gpu); + adreno_show(gpu, m); } #endif diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 624c2a87d593df0174bd5ca4a5fe58e0f8f3492d..b612c9a18faf898e90c70f4df6ca9d8ca25ca44b 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -447,9 +447,9 @@ static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m) seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A4XX_RBBM_STATUS)); + gpu->funcs->pm_suspend(gpu); adreno_show(gpu, m); - gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 765c1c087c76348697c685a7713be112216da2f6..37323e962c2c5b94f7808fe2758fd51e6b006ada 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -15,7 +15,6 @@ #include "msm_iommu.h" #include "msm_trace.h" #include "a5xx_gpu.h" -#include #define SECURE_VA_START 0xc0000000 #define SECURE_VA_SIZE SZ_256M @@ -376,7 +375,6 @@ static const struct { void a5xx_set_hwcg(struct msm_gpu *gpu, bool state) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); unsigned int i; for (i = 0; i < ARRAY_SIZE(a5xx_hwcg); i++) @@ -393,11 +391,6 @@ void a5xx_set_hwcg(struct msm_gpu *gpu, bool state) gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, state ? 0xAAA8AA00 : 0); gpu_write(gpu, REG_A5XX_RBBM_ISDB_CNT, state ? 0x182 : 0x180); - - if (state) - set_bit(A5XX_HWCG_ENABLED, &a5xx_gpu->flags); - else - clear_bit(A5XX_HWCG_ENABLED, &a5xx_gpu->flags); } static int a5xx_me_init(struct msm_gpu *gpu) @@ -1170,26 +1163,11 @@ static int a5xx_pm_resume(struct msm_gpu *gpu) { int ret; - /* - * Between suspend/resumes the GPU clocks need to be turned off - * but not a complete power down, typically between frames. Set the - * memory retention flags on the GPU core clock to retain memory - * across clock toggles. - */ - if (gpu->core_clk) { - clk_set_flags(gpu->core_clk, CLKFLAG_RETAIN_PERIPH); - clk_set_flags(gpu->core_clk, CLKFLAG_RETAIN_MEM); - } - /* Turn on the core power */ ret = msm_gpu_pm_resume(gpu); if (ret) return ret; - /* If we are already up, don't mess with what works */ - if (gpu->active_cnt > 1) - return 0; - /* Turn the RBCCU domain first to limit the chances of voltage droop */ gpu_write(gpu, REG_A5XX_GPMU_RBCCU_POWER_CNTL, 0x778000); @@ -1220,33 +1198,22 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - /* Turn off the memory retention flag when not necessary */ - if (gpu->core_clk) { - clk_set_flags(gpu->core_clk, CLKFLAG_NORETAIN_PERIPH); - clk_set_flags(gpu->core_clk, CLKFLAG_NORETAIN_MEM); - } + /* Clear the VBIF pipe before shutting down */ - /* Only do this next bit if we are about to go down */ - if (gpu->active_cnt == 1) { - /* Clear the VBIF pipe before shutting down */ + gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0xF); + spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 0xF) == 0xF); - gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0xF); - spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 0xF) - == 0xF); + gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); - gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); + /* + * Reset the VBIF before power collapse to avoid issue with FIFO + * entries + */ - /* - * Reset the VBIF before power collapse to avoid issue with FIFO - * entries - */ - if (adreno_is_a530(adreno_gpu)) { - /* These only need to be done for A530 */ - gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, - 0x003C0000); - gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, - 0x00000000); - } + if (adreno_is_a530(adreno_gpu)) { + /* These only need to be done for A530 */ + gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x003C0000); + gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x00000000); } return msm_gpu_pm_suspend(gpu); @@ -1266,29 +1233,13 @@ static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) #ifdef CONFIG_DEBUG_FS static void a5xx_show(struct msm_gpu *gpu, struct seq_file *m) { - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); - bool enabled = test_bit(A5XX_HWCG_ENABLED, &a5xx_gpu->flags); - gpu->funcs->pm_resume(gpu); seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A5XX_RBBM_STATUS)); - - /* - * Temporarily disable hardware clock gating before going into - * adreno_show to avoid issues while reading the registers - */ - - if (enabled) - a5xx_set_hwcg(gpu, false); + gpu->funcs->pm_suspend(gpu); adreno_show(gpu, m); - - if (enabled) - a5xx_set_hwcg(gpu, true); - - gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h index c30b65785ab6bc06d7dec729d1f89c069d47ebe6..f8b00982fe869f1dd28fc57e5326d4251b342789 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h @@ -23,7 +23,6 @@ enum { A5XX_ZAP_SHADER_LOADED = 1, - A5XX_HWCG_ENABLED = 2, }; struct a5xx_gpu { @@ -70,8 +69,6 @@ struct a5xx_gpu { * PREEMPT_NONE - no preemption in progress. Next state START. * PREEMPT_START - The trigger is evaulating if preemption is possible. Next * states: TRIGGERED, NONE - * PREEMPT_ABORT - An intermediate state before moving back to NONE. Next - * state: NONE. * PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next * states: FAULTED, PENDING * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger @@ -83,7 +80,6 @@ struct a5xx_gpu { enum preempt_state { PREEMPT_NONE = 0, PREEMPT_START, - PREEMPT_ABORT, PREEMPT_TRIGGERED, PREEMPT_FAULTED, PREEMPT_PENDING, @@ -187,10 +183,7 @@ int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot); /* Return true if we are in a preempt state */ static inline bool a5xx_in_preempt(struct a5xx_gpu *a5xx_gpu) { - int preempt_state = atomic_read(&a5xx_gpu->preempt_state); - - return !(preempt_state == PREEMPT_NONE || - preempt_state == PREEMPT_ABORT); + return !(atomic_read(&a5xx_gpu->preempt_state) == PREEMPT_NONE); } int a5xx_counters_init(struct adreno_gpu *adreno_gpu); diff --git a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c index 44d4ca35fa09b671ef1d0e0a1670f59ffd04fc18..6ab3ba076c2fd2f91dd8d6b6124df53266e2c0ef 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c @@ -128,20 +128,9 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) * one do nothing except to update the wptr to the latest and greatest */ if (!ring || (a5xx_gpu->cur_ring == ring)) { - /* - * Its possible that while a preemption request is in progress - * from an irq context, a user context trying to submit might - * fail to update the write pointer, because it determines - * that the preempt state is not PREEMPT_NONE. - * - * Close the race by introducing an intermediate - * state PREEMPT_ABORT to let the submit path - * know that the ringbuffer is not going to change - * and can safely update the write pointer. - */ - - set_preempt_state(a5xx_gpu, PREEMPT_ABORT); - update_wptr(gpu, a5xx_gpu->cur_ring); + update_wptr(gpu, ring); + + /* Set the state back to NONE */ set_preempt_state(a5xx_gpu, PREEMPT_NONE); return; } diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 4e4709d6172f52c1421c82c4612b86db92e242ee..a498a60cd52d13338b87416347fb633abb3984b5 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -173,9 +173,6 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) ret = gpu->funcs->hw_init(gpu); if (ret) { dev_err(dev->dev, "gpu hw init failed: %d\n", ret); - mutex_lock(&dev->struct_mutex); - gpu->funcs->pm_suspend(gpu); - mutex_unlock(&dev->struct_mutex); gpu->funcs->destroy(gpu); gpu = NULL; } else { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 04e0056f2a49002641257881d1690a7f0712f551..2273b06b59a63204326e7e9b15d101520833fcb1 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -297,6 +297,8 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) seq_printf(m, "rb wptr: %d\n", get_wptr(ring)); } + gpu->funcs->pm_resume(gpu); + /* dump these out in a form that can be parsed by demsm: */ seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name); for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { @@ -309,6 +311,8 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) seq_printf(m, "IO:R %08x %08x\n", addr<<2, val); } } + + gpu->funcs->pm_suspend(gpu); } #endif diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index e2b8deda46c2f55b1522fc50ea799d7d2ee32ceb..db37a7c85bda3f9aea350cca44356c8a6bd4459f 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index f1f955f571fa1fa277da91ffc830726edebe32e8..a87f898707a3d887e19c8b3b414d5f2c298b568a 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index fa111d581529c57cc97ede7a1885526ac6b59067..2ee75a2c1039b7c7ee6e464dc7052d9efecdda9b 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -556,13 +556,13 @@ static const struct file_operations sde_hdmi_hdcp_state_fops = { .read = _sde_hdmi_hdcp_state_read, }; -static u64 _sde_hdmi_clip_valid_pclk(struct hdmi *hdmi, u64 pclk_in) +static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in) { u32 pclk_delta, pclk; u64 pclk_clip = pclk_in; /* as per standard, 0.5% of deviation is allowed */ - pclk = hdmi->pixclock; + pclk = mode->clock * HDMI_KHZ_TO_HZ; pclk_delta = pclk * 5 / 1000; if (pclk_in < (pclk - pclk_delta)) @@ -700,6 +700,7 @@ static void sde_hdmi_tx_hdcp_cb_work(struct work_struct *work) static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm) { struct hdmi *hdmi = display->ctrl.ctrl; + struct drm_display_mode *current_mode = &display->mode; u64 cur_pclk, dst_pclk; u64 clip_pclk; int rc = 0; @@ -724,7 +725,7 @@ static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm) dst_pclk = cur_pclk * (1000000000 + ppm); do_div(dst_pclk, 1000000000); - clip_pclk = _sde_hdmi_clip_valid_pclk(hdmi, dst_pclk); + clip_pclk = _sde_hdmi_clip_valid_pclk(current_mode, dst_pclk); /* update pclk */ if (clip_pclk != cur_pclk) { @@ -1253,13 +1254,6 @@ static int _sde_hdmi_hpd_enable(struct sde_hdmi *sde_hdmi) uint32_t hpd_ctrl; int i, ret; unsigned long flags; - struct drm_connector *connector; - struct msm_drm_private *priv; - struct sde_kms *sde_kms; - - connector = hdmi->connector; - priv = connector->dev->dev_private; - sde_kms = to_sde_kms(priv->kms); for (i = 0; i < config->hpd_reg_cnt; i++) { ret = regulator_enable(hdmi->hpd_regs[i]); @@ -1299,11 +1293,9 @@ static int _sde_hdmi_hpd_enable(struct sde_hdmi *sde_hdmi) } } - if (!sde_kms->splash_info.handoff) { - sde_hdmi_set_mode(hdmi, false); - _sde_hdmi_phy_reset(hdmi); - sde_hdmi_set_mode(hdmi, true); - } + sde_hdmi_set_mode(hdmi, false); + _sde_hdmi_phy_reset(hdmi); + sde_hdmi_set_mode(hdmi, true); hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b); @@ -1901,6 +1893,11 @@ struct drm_msm_ext_panel_hdr_metadata *hdr_meta) return; } + if (!connector->hdr_supported) { + SDE_ERROR("Sink does not support HDR\n"); + return; + } + /* Setup Packet header and payload */ packet_header = type_code | (version << 8) | (length << 16); hdmi_write(hdmi, HDMI_GENERIC0_HDR, packet_header); @@ -1970,147 +1967,6 @@ enable_packet_control: hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); } -static void sde_hdmi_update_colorimetry(struct sde_hdmi *display, - bool use_bt2020) -{ - struct hdmi *hdmi; - struct drm_connector *connector; - bool mode_is_yuv = false; - struct drm_display_mode *mode; - u32 mode_fmt_flags = 0; - u8 checksum; - u32 avi_info0 = 0; - u32 avi_info1 = 0; - u8 avi_iframe[HDMI_AVI_INFOFRAME_BUFFER_SIZE] = {0}; - u8 *avi_frame = &avi_iframe[HDMI_INFOFRAME_HEADER_SIZE]; - struct hdmi_avi_infoframe info; - - if (!display) { - SDE_ERROR("invalid input\n"); - return; - } - - hdmi = display->ctrl.ctrl; - - if (!hdmi) { - SDE_ERROR("invalid input\n"); - return; - } - - connector = display->ctrl.ctrl->connector; - - if (!connector) { - SDE_ERROR("invalid input\n"); - return; - } - - if (!connector->hdr_supported) { - SDE_DEBUG("HDR is not supported\n"); - return; - } - - /* If sink doesn't support BT2020, just return */ - if (!(connector->color_enc_fmt & DRM_EDID_COLORIMETRY_BT2020_YCC) || - !(connector->color_enc_fmt & DRM_EDID_COLORIMETRY_BT2020_RGB)) { - SDE_DEBUG("BT2020 colorimetry is not supported\n"); - return; - } - - /* If there is no change in colorimetry, just return */ - if (use_bt2020 && display->bt2020_colorimetry) - return; - else if (!use_bt2020 && !display->bt2020_colorimetry) - return; - - mode = &display->mode; - /* Cache the format flags before clearing */ - mode_fmt_flags = mode->flags; - /** - * Clear the RGB/YUV format flags before calling upstream API - * as the API also compares the flags and then returns a mode - */ - mode->flags &= ~SDE_DRM_MODE_FLAG_FMT_MASK; - drm_hdmi_avi_infoframe_from_display_mode(&info, mode); - /* Restore the format flags */ - mode->flags = mode_fmt_flags; - - /* Mode should only support YUV and not both to set the flag */ - if ((mode->private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420) - && !(mode->private_flags & MSM_MODE_FLAG_COLOR_FORMAT_RGB444)) { - mode_is_yuv = true; - } - - - if (!display->bt2020_colorimetry && use_bt2020) { - /** - * 1. Update colorimetry to use extended - * 2. Change extended to use BT2020 - * 3. Change colorspace based on mode - * 4. Use limited as BT2020 is always limited - */ - info.colorimetry = SDE_HDMI_USE_EXTENDED_COLORIMETRY; - info.extended_colorimetry = SDE_HDMI_BT2020_COLORIMETRY; - if (mode_is_yuv) - info.colorspace = HDMI_COLORSPACE_YUV420; - if (connector->yuv_qs) - info.ycc_quantization_range = - HDMI_YCC_QUANTIZATION_RANGE_LIMITED; - } else if (display->bt2020_colorimetry && !use_bt2020) { - /** - * 1. Update colorimetry to non-extended - * 2. Change colorspace based on mode - * 3. Restore quantization to full if QS - * is enabled - */ - info.colorimetry = SDE_HDMI_DEFAULT_COLORIMETRY; - if (mode_is_yuv) - info.colorspace = HDMI_COLORSPACE_YUV420; - if (connector->yuv_qs) - info.ycc_quantization_range = - HDMI_YCC_QUANTIZATION_RANGE_FULL; - } - - hdmi_avi_infoframe_pack(&info, avi_iframe, sizeof(avi_iframe)); - checksum = avi_iframe[HDMI_INFOFRAME_HEADER_SIZE - 1]; - avi_info0 = checksum | - LEFT_SHIFT_BYTE(avi_frame[0]) | - LEFT_SHIFT_WORD(avi_frame[1]) | - LEFT_SHIFT_24BITS(avi_frame[2]); - - avi_info1 = avi_frame[3] | - LEFT_SHIFT_BYTE(avi_frame[4]) | - LEFT_SHIFT_WORD(avi_frame[5]) | - LEFT_SHIFT_24BITS(avi_frame[6]); - - hdmi_write(hdmi, REG_HDMI_AVI_INFO(0), avi_info0); - hdmi_write(hdmi, REG_HDMI_AVI_INFO(1), avi_info1); - display->bt2020_colorimetry = use_bt2020; -} - -static void sde_hdmi_clear_hdr_infoframe(struct sde_hdmi *display) -{ - struct hdmi *hdmi; - struct drm_connector *connector; - u32 packet_control = 0; - - if (!display) { - SDE_ERROR("invalid input\n"); - return; - } - - hdmi = display->ctrl.ctrl; - connector = display->ctrl.ctrl->connector; - - if (!hdmi || !connector) { - SDE_ERROR("invalid input\n"); - return; - } - - packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); - packet_control &= ~HDMI_GEN_PKT_CTRL_CLR_MASK; - hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); -} - int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, @@ -2153,8 +2009,6 @@ int sde_hdmi_get_property(struct drm_connector *connector, mutex_lock(&hdmi_display->display_lock); if (property_index == CONNECTOR_PROP_PLL_ENABLE) *value = hdmi_display->pll_update_enable ? 1 : 0; - if (property_index == CONNECTOR_PROP_HDCP_VERSION) - *value = hdmi_display->sink_hdcp_ver; mutex_unlock(&hdmi_display->display_lock); return rc; @@ -2277,13 +2131,9 @@ static int sde_hdmi_tx_check_capability(struct sde_hdmi *sde_hdmi) } } - if (sde_hdmi->hdmi_tx_major_version >= HDMI_TX_VERSION_4) - sde_hdmi->dc_feature_supported = true; - - SDE_DEBUG("%s: Features \n", __func__, + SDE_DEBUG("%s: Features \n", __func__, hdmi_disabled ? "OFF" : "ON", - hdcp_disabled ? "OFF" : "ON", - sde_hdmi->dc_feature_supported ? "ON" : "OFF"); + hdcp_disabled ? "OFF" : "ON"); if (hdmi_disabled) { DEV_ERR("%s: HDMI disabled\n", __func__); @@ -2457,110 +2307,13 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector, void *display, struct msm_display_kickoff_params *params) { - struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; - struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; - struct drm_msm_ext_panel_hdr_metadata *hdr_meta; - u8 hdr_op; - - if (!connector || !display || !params || - !params->hdr_ctrl) { - pr_err("Invalid params\n"); - return -EINVAL; - } - hdr_ctrl = params->hdr_ctrl; - hdr_meta = &hdr_ctrl->hdr_meta; - - if (!hdr_meta) { - SDE_ERROR("Invalid params\n"); - return -EINVAL; - } - - hdr_op = sde_hdmi_hdr_get_ops(hdmi_display->curr_hdr_state, - hdr_ctrl->hdr_state); - - if (hdr_op == HDR_SEND_INFO) { - if (connector->hdr_supported) - sde_hdmi_panel_set_hdr_infoframe(display, - &hdr_ctrl->hdr_meta); - if (hdr_meta->eotf) - sde_hdmi_update_colorimetry(hdmi_display, - true); - else - sde_hdmi_update_colorimetry(hdmi_display, - false); - } else if (hdr_op == HDR_CLEAR_INFO) - sde_hdmi_clear_hdr_infoframe(display); - - hdmi_display->curr_hdr_state = hdr_ctrl->hdr_state; + sde_hdmi_panel_set_hdr_infoframe(display, + params->hdr_metadata); return 0; } -bool sde_hdmi_mode_needs_full_range(void *display) -{ - struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; - struct drm_display_mode *mode; - u32 mode_fmt_flags = 0; - u32 cea_mode; - - if (!hdmi_display) { - SDE_ERROR("invalid input\n"); - return false; - } - - mode = &hdmi_display->mode; - /* Cache the format flags before clearing */ - mode_fmt_flags = mode->flags; - /** - * Clear the RGB/YUV format flags before calling upstream API - * as the API also compares the flags and then returns a mode - */ - mode->flags &= ~SDE_DRM_MODE_FLAG_FMT_MASK; - cea_mode = drm_match_cea_mode(mode); - /* Restore the format flags */ - mode->flags = mode_fmt_flags; - - if (cea_mode > SDE_HDMI_VIC_640x480) - return false; - - return true; -} - -enum sde_csc_type sde_hdmi_get_csc_type(struct drm_connector *conn, - void *display) -{ - struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; - struct sde_connector_state *c_state; - struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; - struct drm_msm_ext_panel_hdr_metadata *hdr_meta; - - if (!hdmi_display || !conn) { - SDE_ERROR("invalid input\n"); - goto error; - } - - c_state = to_sde_connector_state(conn->state); - - if (!c_state) { - SDE_ERROR("invalid input\n"); - goto error; - } - - hdr_ctrl = &c_state->hdr_ctrl; - hdr_meta = &hdr_ctrl->hdr_meta; - - if ((hdr_ctrl->hdr_state == HDR_ENABLE) - && (hdr_meta->eotf != 0)) - return SDE_CSC_RGB2YUV_2020L; - else if (sde_hdmi_mode_needs_full_range(hdmi_display) - || conn->yuv_qs) - return SDE_CSC_RGB2YUV_601FR; - -error: - return SDE_CSC_RGB2YUV_601L; -} - int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display) { struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; @@ -3069,7 +2822,6 @@ int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) struct msm_drm_private *priv = NULL; struct hdmi *hdmi; struct platform_device *pdev; - struct sde_kms *sde_kms; DBG(""); if (!display || !display->drm_dev || !enc) { @@ -3128,19 +2880,6 @@ int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) enc->bridge = hdmi->bridge; priv->bridges[priv->num_bridges++] = hdmi->bridge; - /* - * After initialising HDMI bridge, we need to check - * whether the early display is enabled for HDMI. - * If yes, we need to increase refcount of hdmi power - * clocks. This can skip the clock disabling operation in - * clock_late_init when finding clk.count == 1. - */ - sde_kms = to_sde_kms(priv->kms); - if (sde_kms->splash_info.handoff) { - sde_hdmi_bridge_power_on(hdmi->bridge); - hdmi->power_on = true; - } - mutex_unlock(&display->display_lock); return 0; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index 865998c6a126ef045eaa703dd7a5edd0170e8ffd..6b9bcfec031b11f92dbfcba2302c14c34297f620 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -33,9 +33,6 @@ #include "sde_hdmi_util.h" #include "sde_hdcp.h" -#ifndef MIN -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -#endif #ifdef HDMI_DEBUG_ENABLE #define SDE_HDMI_DEBUG(fmt, args...) SDE_ERROR(fmt, ##args) #else @@ -108,34 +105,12 @@ enum hdmi_tx_feature_type { * @mode: Current display mode. * @connected: If HDMI display is connected. * @is_tpg_enabled: TPG state. - * @hdmi_tx_version: HDMI TX version - * @hdmi_tx_major_version: HDMI TX major version - * @max_pclk_khz: Max pixel clock supported - * @hdcp1_use_sw_keys: If HDCP1 engine uses SW keys - * @hdcp14_present: If the sink supports HDCP 1.4 - * @hdcp22_present: If the sink supports HDCP 2.2 - * @hdcp_status: Current HDCP status - * @sink_hdcp_ver: HDCP version of the sink - * @enc_lvl: Current encryption level - * @curr_hdr_state: Current HDR state of the HDMI connector - * @auth_state: Current authentication state of HDCP - * @sink_hdcp22_support: If the sink supports HDCP 2.2 - * @src_hdcp22_support: If the source supports HDCP 2.2 - * @hdcp_data: Call back data registered by the client with HDCP lib - * @hdcp_feat_data: Handle to HDCP feature data - * @hdcp_ops: Function ops registered by the client with the HDCP lib - * @ddc_ctrl: Handle to HDMI DDC Controller * @hpd_work: HPD work structure. * @codec_ready: If audio codec is ready. * @client_notify_pending: If there is client notification pending. * @irq_domain: IRQ domain structure. - * @notifier: CEC notifider to convey physical address information. * @pll_update_enable: if it's allowed to update HDMI PLL ppm. - * @dc_enable: If deep color is enabled. Only DC_30 so far. - * @dc_feature_supported: If deep color feature is supported. - * @bt2020_colorimetry: If BT2020 colorimetry is supported by sink - * @hdcp_cb_work: Callback function for HDCP - * @io: Handle to IO base addresses for HDMI + * @notifier: CEC notifider to convey physical address information. * @root: Debug fs root entry. */ struct sde_hdmi { @@ -166,9 +141,7 @@ struct sde_hdmi { u32 hdcp14_present; u32 hdcp22_present; u8 hdcp_status; - u8 sink_hdcp_ver; u32 enc_lvl; - u8 curr_hdr_state; bool auth_state; bool sink_hdcp22_support; bool src_hdcp22_support; @@ -188,9 +161,6 @@ struct sde_hdmi { struct irq_domain *irq_domain; struct cec_notifier *notifier; bool pll_update_enable; - bool dc_enable; - bool dc_feature_supported; - bool bt2020_colorimetry; struct delayed_work hdcp_cb_work; struct dss_io_data io[HDMI_TX_MAX_IO]; @@ -218,19 +188,6 @@ enum hdmi_tx_scdc_access_type { #define HDMI_KHZ_TO_HZ 1000 #define HDMI_MHZ_TO_HZ 1000000 -#define HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2 -#define HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1 - -#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x7 - -/* for AVI program */ -#define HDMI_AVI_INFOFRAME_BUFFER_SIZE \ - (HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE) -#define HDMI_VS_INFOFRAME_BUFFER_SIZE (HDMI_INFOFRAME_HEADER_SIZE + 6) - -#define LEFT_SHIFT_BYTE(x) ((x) << 8) -#define LEFT_SHIFT_WORD(x) ((x) << 16) -#define LEFT_SHIFT_24BITS(x) ((x) << 24) /* Maximum pixel clock rates for hdmi tx */ #define HDMI_DEFAULT_MAX_PCLK_RATE 148500 @@ -388,13 +345,6 @@ int sde_hdmi_set_property(struct drm_connector *connector, int property_index, uint64_t value, void *display); -/** - * sde_hdmi_bridge_power_on -- A wrapper of _sde_hdmi_bridge_power_on. - * @bridge: Handle to the drm bridge. - * - * Return: void. - */ -void sde_hdmi_bridge_power_on(struct drm_bridge *bridge); /** * sde_hdmi_get_property() - get the connector properties @@ -513,23 +463,6 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector, void *display, struct msm_display_kickoff_params *params); -/* - * sde_hdmi_mode_needs_full_range - does mode need full range - * quantization - * @display: Pointer to private display structure - * Returns: true or false based on mode - */ -bool sde_hdmi_mode_needs_full_range(void *display); - -/* - * sde_hdmi_get_csc_type - returns the CSC type to be - * used based on state of HDR playback - * @conn: Pointer to DRM connector - * @display: Pointer to private display structure - * Returns: true or false based on mode - */ -enum sde_csc_type sde_hdmi_get_csc_type(struct drm_connector *conn, - void *display); #else /*#ifdef CONFIG_DRM_SDE_HDMI*/ static inline u32 sde_hdmi_get_num_of_displays(void) @@ -644,16 +577,5 @@ static inline int sde_hdmi_set_property(struct drm_connector *connector, return 0; } -static inline bool sde_hdmi_mode_needs_full_range(void *display) -{ - return false; -} - -enum sde_csc_type sde_hdmi_get_csc_type(struct drm_connector *conn, - void *display) -{ - return 0; -} - #endif /*#else of CONFIG_DRM_SDE_HDMI*/ #endif /* _SDE_HDMI_H_ */ diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index 3c470caec571981c812ac459d87e8ac6a93c0050..24d2320683e42bf24564406a8eabe80047d76b54 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -99,10 +99,17 @@ struct sde_hdmi_bridge { #define HDMI_TX_SCRAMBLER_TIMEOUT_MSEC 200 +/* for AVI program */ +#define HDMI_AVI_INFOFRAME_BUFFER_SIZE \ + (HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE) +#define HDMI_VS_INFOFRAME_BUFFER_SIZE (HDMI_INFOFRAME_HEADER_SIZE + 6) #define HDMI_SPD_INFOFRAME_BUFFER_SIZE \ (HDMI_INFOFRAME_HEADER_SIZE + HDMI_SPD_INFOFRAME_SIZE) #define HDMI_DEFAULT_VENDOR_NAME "unknown" #define HDMI_DEFAULT_PRODUCT_NAME "msm" +#define LEFT_SHIFT_BYTE(x) ((x) << 8) +#define LEFT_SHIFT_WORD(x) ((x) << 16) +#define LEFT_SHIFT_24BITS(x) ((x) << 24) #define HDMI_AVI_IFRAME_LINE_NUMBER 1 #define HDMI_VENDOR_IFRAME_LINE_NUMBER 3 @@ -338,13 +345,10 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi, return 0; } - /* use actual clock instead of mode clock */ - if (hdmi->pixclock > - HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ * HDMI_KHZ_TO_HZ) { + if (mode->clock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) { scrambler_on = true; tmds_clock_ratio = 1; } else { - tmds_clock_ratio = 0; scrambler_on = connector->supports_scramble; } @@ -390,14 +394,6 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi, rc = _sde_hdmi_bridge_setup_ddc_timers(hdmi, HDMI_TX_DDC_TIMER_SCRAMBLER_STATUS, timeout_hsync); } else { - /* reset tmds clock ratio */ - rc = sde_hdmi_scdc_write(hdmi, - HDMI_TX_SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE, - tmds_clock_ratio); - /* scdc write can fail if sink doesn't support SCDC */ - if (rc && connector->scdc_present) - SDE_ERROR("SCDC present, TMDS clk ratio err\n"); - sde_hdmi_scdc_write(hdmi, HDMI_TX_SCDC_SCRAMBLING_ENABLE, 0x0); reg_val = hdmi_read(hdmi, REG_HDMI_CTRL); reg_val &= ~BIT(28); /* Unset SCRAMBLER_EN bit */ @@ -406,38 +402,6 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi, return rc; } -static void _sde_hdmi_bridge_setup_deep_color(struct hdmi *hdmi) -{ - struct drm_connector *connector = hdmi->connector; - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; - u32 hdmi_ctrl_reg, vbi_pkt_reg; - - SDE_DEBUG("Deep Color: %s\n", display->dc_enable ? "On" : "Off"); - - if (display->dc_enable) { - hdmi_ctrl_reg = hdmi_read(hdmi, REG_HDMI_CTRL); - - /* GC CD override */ - hdmi_ctrl_reg |= BIT(27); - - /* enable deep color for RGB888/YUV444/YUV420 30 bits */ - hdmi_ctrl_reg |= BIT(24); - hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl_reg); - /* Enable GC_CONT and GC_SEND in General Control Packet - * (GCP) register so that deep color data is - * transmitted to the sink on every frame, allowing - * the sink to decode the data correctly. - * - * GC_CONT: 0x1 - Send GCP on every frame - * GC_SEND: 0x1 - Enable GCP Transmission - */ - vbi_pkt_reg = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL); - vbi_pkt_reg |= BIT(5) | BIT(4); - hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_reg); - } -} - static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); @@ -511,11 +475,6 @@ static void sde_hdmi_update_hdcp_info(struct drm_connector *connector) } } - if (display->sink_hdcp22_support) - display->sink_hdcp_ver = SDE_HDMI_HDCP_22; - else - display->sink_hdcp_ver = SDE_HDMI_HDCP_14; - /* update internal data about hdcp */ display->hdcp_data = fd; display->hdcp_ops = ops; @@ -525,17 +484,12 @@ static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; - struct sde_connector *c_conn = to_sde_connector(hdmi->connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; /* need to update hdcp info here to ensure right HDCP support*/ sde_hdmi_update_hdcp_info(hdmi->connector); /* start HDCP authentication */ sde_hdmi_start_hdcp(hdmi->connector); - - /* reset HDR state */ - display->curr_hdr_state = HDR_DISABLE; } static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) @@ -548,7 +502,6 @@ static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) mutex_lock(&display->display_lock); display->pll_update_enable = false; - display->sink_hdcp_ver = SDE_HDMI_HDCP_NONE; mutex_unlock(&display->display_lock); } @@ -581,50 +534,15 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) } static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { u8 avi_iframe[HDMI_AVI_INFOFRAME_BUFFER_SIZE] = {0}; u8 *avi_frame = &avi_iframe[HDMI_INFOFRAME_HEADER_SIZE]; u8 checksum; u32 reg_val; - u32 mode_fmt_flags = 0; struct hdmi_avi_infoframe info; - struct drm_connector *connector; - - if (!hdmi || !mode) { - SDE_ERROR("invalid input\n"); - return; - } - - connector = hdmi->connector; - - if (!connector) { - SDE_ERROR("invalid input\n"); - return; - } - /* Cache the format flags before clearing */ - mode_fmt_flags = mode->flags; - /** - * Clear the RGB/YUV format flags before calling upstream API - * as the API also compares the flags and then returns a mode - */ - mode->flags &= ~SDE_DRM_MODE_FLAG_FMT_MASK; drm_hdmi_avi_infoframe_from_display_mode(&info, mode); - /* Restore the format flags */ - mode->flags = mode_fmt_flags; - - if (mode->private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420) { - info.colorspace = HDMI_COLORSPACE_YUV420; - /** - * If sink supports quantization select, - * override to full range - */ - if (connector->yuv_qs) - info.ycc_quantization_range = - HDMI_YCC_QUANTIZATION_RANGE_FULL; - } - hdmi_avi_infoframe_pack(&info, avi_iframe, sizeof(avi_iframe)); checksum = avi_iframe[HDMI_INFOFRAME_HEADER_SIZE - 1]; @@ -742,77 +660,31 @@ static inline void _sde_hdmi_save_mode(struct hdmi *hdmi, drm_mode_copy(&display->mode, mode); } -static u32 _sde_hdmi_choose_best_format(struct hdmi *hdmi, - struct drm_display_mode *mode) -{ - /* - * choose priority: - * 1. DC + RGB - * 2. DC + YUV - * 3. RGB - * 4. YUV - */ - int dc_format; - struct drm_connector *connector = hdmi->connector; - - dc_format = sde_hdmi_sink_dc_support(connector, mode); - if (dc_format & MSM_MODE_FLAG_RGB444_DC_ENABLE) - return (MSM_MODE_FLAG_COLOR_FORMAT_RGB444 - | MSM_MODE_FLAG_RGB444_DC_ENABLE); - else if (dc_format & MSM_MODE_FLAG_YUV420_DC_ENABLE) - return (MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420 - | MSM_MODE_FLAG_YUV420_DC_ENABLE); - else if (mode->flags & DRM_MODE_FLAG_SUPPORTS_RGB) - return MSM_MODE_FLAG_COLOR_FORMAT_RGB444; - else if (mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV) - return MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420; - - SDE_ERROR("Can't get available best display format\n"); - - return MSM_MODE_FLAG_COLOR_FORMAT_RGB444; -} - static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; - struct drm_connector *connector = hdmi->connector; - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; int hstart, hend, vstart, vend; uint32_t frame_ctrl; - u32 div = 0; mode = adjusted_mode; - display->dc_enable = mode->private_flags & - (MSM_MODE_FLAG_RGB444_DC_ENABLE | - MSM_MODE_FLAG_YUV420_DC_ENABLE); - /* compute pixclock as per color format and bit depth */ - hdmi->pixclock = sde_hdmi_calc_pixclk( - mode->clock * HDMI_KHZ_TO_HZ, - mode->private_flags, - display->dc_enable); - SDE_DEBUG("Actual PCLK: %lu, Mode PCLK: %d\n", - hdmi->pixclock, mode->clock); + hdmi->pixclock = mode->clock * 1000; - if (mode->private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420) - div = 1; - - hstart = (mode->htotal - mode->hsync_start) >> div; - hend = (mode->htotal - mode->hsync_start + mode->hdisplay) >> div; + hstart = mode->htotal - mode->hsync_start; + hend = mode->htotal - mode->hsync_start + mode->hdisplay; vstart = mode->vtotal - mode->vsync_start - 1; vend = mode->vtotal - mode->vsync_start + mode->vdisplay - 1; - SDE_DEBUG( + DRM_DEBUG( "htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d", mode->htotal, mode->vtotal, hstart, hend, vstart, vend); hdmi_write(hdmi, REG_HDMI_TOTAL, - SDE_HDMI_TOTAL_H_TOTAL((mode->htotal >> div) - 1) | + SDE_HDMI_TOTAL_H_TOTAL(mode->htotal - 1) | SDE_HDMI_TOTAL_V_TOTAL(mode->vtotal - 1)); hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC, @@ -862,27 +734,6 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge, _sde_hdmi_save_mode(hdmi, mode); _sde_hdmi_bridge_setup_scrambler(hdmi, mode); - _sde_hdmi_bridge_setup_deep_color(hdmi); -} - -static bool _sde_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); - struct hdmi *hdmi = sde_hdmi_bridge->hdmi; - - adjusted_mode->private_flags |= - _sde_hdmi_choose_best_format(hdmi, adjusted_mode); - SDE_DEBUG("Adjusted mode private flags: 0x%x\n", - adjusted_mode->private_flags); - - return true; -} - -void sde_hdmi_bridge_power_on(struct drm_bridge *bridge) -{ - _sde_hdmi_bridge_power_on(bridge); } static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = { @@ -891,7 +742,6 @@ static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = { .disable = _sde_hdmi_bridge_disable, .post_disable = _sde_hdmi_bridge_post_disable, .mode_set = _sde_hdmi_bridge_mode_set, - .mode_fixup = _sde_hdmi_bridge_mode_fixup, }; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c index a291a1112aeb9a21273bc01400a28e230bc54176..a7887d2c84b0a4c3ee5403392124df7b8a03d7c7 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c @@ -68,15 +68,6 @@ static void sde_hdmi_hdcp2p2_ddc_clear_status(struct sde_hdmi *display) hdmi_write(hdmi, HDMI_HDCP2P2_DDC_STATUS, reg_val); } -static const char *sde_hdmi_hdr_sname(enum sde_hdmi_hdr_state hdr_state) -{ - switch (hdr_state) { - case HDR_DISABLE: return "HDR_DISABLE"; - case HDR_ENABLE: return "HDR_ENABLE"; - default: return "HDR_INVALID_STATE"; - } -} - /** * sde_hdmi_dump_regs - utility to dump HDMI regs * @hdmi_display: Pointer to private display handle @@ -834,123 +825,3 @@ int sde_hdmi_hdcp2p2_read_rxstatus(void *hdmi_display) } return rc; } - -unsigned long sde_hdmi_calc_pixclk(unsigned long pixel_freq, - u32 out_format, bool dc_enable) -{ - u32 rate_ratio = HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO; - - if (out_format & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420) - rate_ratio = HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO; - - pixel_freq /= rate_ratio; - - if (dc_enable) - pixel_freq += pixel_freq >> 2; - - return pixel_freq; - -} - -bool sde_hdmi_validate_pixclk(struct drm_connector *connector, - unsigned long pclk) -{ - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; - unsigned long max_pclk = display->max_pclk_khz * HDMI_KHZ_TO_HZ; - - if (connector->max_tmds_char) - max_pclk = MIN(max_pclk, - connector->max_tmds_char * HDMI_MHZ_TO_HZ); - else if (connector->max_tmds_clock) - max_pclk = MIN(max_pclk, - connector->max_tmds_clock * HDMI_MHZ_TO_HZ); - - SDE_DEBUG("MAX PCLK = %ld, PCLK = %ld\n", max_pclk, pclk); - - return pclk < max_pclk; -} - -static bool sde_hdmi_check_dc_clock(struct drm_connector *connector, - struct drm_display_mode *mode, u32 format) -{ - struct sde_connector *c_conn = to_sde_connector(connector); - struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; - - u32 tmds_clk_with_dc = sde_hdmi_calc_pixclk( - mode->clock * HDMI_KHZ_TO_HZ, - format, - true); - - return (display->dc_feature_supported && - sde_hdmi_validate_pixclk(connector, tmds_clk_with_dc)); -} - -int sde_hdmi_sink_dc_support(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - int dc_format = 0; - - if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV) && - (connector->display_info.edid_hdmi_dc_modes - & DRM_EDID_YCBCR420_DC_30)) - if (sde_hdmi_check_dc_clock(connector, mode, - MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420)) - dc_format |= MSM_MODE_FLAG_YUV420_DC_ENABLE; - - if ((mode->flags & DRM_MODE_FLAG_SUPPORTS_RGB) && - (connector->display_info.edid_hdmi_dc_modes - & DRM_EDID_HDMI_DC_30)) - if (sde_hdmi_check_dc_clock(connector, mode, - MSM_MODE_FLAG_COLOR_FORMAT_RGB444)) - dc_format |= MSM_MODE_FLAG_RGB444_DC_ENABLE; - - return dc_format; -} - -u8 sde_hdmi_hdr_get_ops(u8 curr_state, - u8 new_state) -{ - - /** There could be 3 valid state transitions: - * 1. HDR_DISABLE -> HDR_ENABLE - * - * In this transition, we shall start sending - * HDR metadata with metadata from the HDR clip - * - * 2. HDR_ENABLE -> HDR_ENABLE - * - * In this transition, we will keep sending - * HDR metadata but with EOTF and metadata as 0 - * - * 3. HDR_ENABLE -> HDR_DISABLE - * - * In this transition, we will stop sending - * metadata to the sink and clear PKT_CTRL register - * bits. - */ - - if ((curr_state == HDR_DISABLE) - && (new_state == HDR_ENABLE)) { - HDMI_UTIL_DEBUG("State changed %s ---> %s\n", - sde_hdmi_hdr_sname(curr_state), - sde_hdmi_hdr_sname(new_state)); - return HDR_SEND_INFO; - } else if ((curr_state == HDR_ENABLE) - && (new_state == HDR_ENABLE)) { - HDMI_UTIL_DEBUG("State changed %s ---> %s\n", - sde_hdmi_hdr_sname(curr_state), - sde_hdmi_hdr_sname(new_state)); - return HDR_SEND_INFO; - } else if ((curr_state == HDR_ENABLE) - && (new_state == HDR_DISABLE)) { - HDMI_UTIL_DEBUG("State changed %s ---> %s\n", - sde_hdmi_hdr_sname(curr_state), - sde_hdmi_hdr_sname(new_state)); - return HDR_CLEAR_INFO; - } - - HDMI_UTIL_DEBUG("Unsupported OR no state change\n"); - return HDR_UNSUPPORTED_OP; -} - diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h index 421bdf7643cad85d0a08ac83a3e1c5a793c46334..8b69dd31f63707bdb12e9ec1bf44ba52b7d40641 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h @@ -97,18 +97,6 @@ #define HDMI_GET_MSB(x)(x >> 8) #define HDMI_GET_LSB(x)(x & 0xff) -#define SDE_HDMI_VIC_640x480 0x1 -#define SDE_HDMI_YCC_QUANT_MASK (0x3 << 14) -#define SDE_HDMI_COLORIMETRY_MASK (0x3 << 22) - -#define SDE_HDMI_DEFAULT_COLORIMETRY 0x0 -#define SDE_HDMI_USE_EXTENDED_COLORIMETRY 0x3 -#define SDE_HDMI_BT2020_COLORIMETRY 0x6 - -#define SDE_HDMI_HDCP_22 0x22 -#define SDE_HDMI_HDCP_14 0x14 -#define SDE_HDMI_HDCP_NONE 0x0 - /* * Bits 1:0 in HDMI_HW_DDC_CTRL that dictate how the HDCP 2.2 RxStatus will be * read by the hardware @@ -137,17 +125,6 @@ enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask { RXSTATUS_REAUTH_REQ = BIT(14), }; -enum sde_hdmi_hdr_state { - HDR_DISABLE, - HDR_ENABLE -}; - -enum sde_hdmi_hdr_op { - HDR_UNSUPPORTED_OP, - HDR_SEND_INFO, - HDR_CLEAR_INFO -}; - struct sde_hdmi_tx_hdcp2p2_ddc_data { enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask; u32 timeout_ms; @@ -187,12 +164,4 @@ int sde_hdmi_hdcp2p2_read_rxstatus(void *hdmi_display); void sde_hdmi_ddc_config(void *hdmi_display); int sde_hdmi_ddc_hdcp2p2_isr(void *hdmi_display); void sde_hdmi_dump_regs(void *hdmi_display); -unsigned long sde_hdmi_calc_pixclk(unsigned long pixel_freq, - u32 out_format, bool dc_enable); -bool sde_hdmi_validate_pixclk(struct drm_connector *connector, - unsigned long pclk); -int sde_hdmi_sink_dc_support(struct drm_connector *connector, - struct drm_display_mode *mode); -u8 sde_hdmi_hdr_get_ops(u8 curr_state, - u8 new_state); #endif /* _SDE_HDMI_UTIL_H_ */ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index c8b11425a817b658ae4366ab0e9fe2444b26beb6..924ce64206f4f8899618d5b711aacba7df5ce58c 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1923,75 +1923,8 @@ static struct drm_driver msm_driver = { #ifdef CONFIG_PM_SLEEP static int msm_pm_suspend(struct device *dev) { - struct drm_device *ddev; - struct drm_modeset_acquire_ctx *ctx; - struct drm_connector *conn; - struct drm_atomic_state *state; - struct drm_crtc_state *crtc_state; - struct msm_drm_private *priv; - int ret = 0; - - if (!dev) - return -EINVAL; - - ddev = dev_get_drvdata(dev); - if (!ddev || !ddev->dev_private) - return -EINVAL; - - priv = ddev->dev_private; - SDE_EVT32(0); - - /* acquire modeset lock(s) */ - drm_modeset_lock_all(ddev); - ctx = ddev->mode_config.acquire_ctx; - - /* save current state for resume */ - if (priv->suspend_state) - drm_atomic_state_free(priv->suspend_state); - priv->suspend_state = drm_atomic_helper_duplicate_state(ddev, ctx); - if (IS_ERR_OR_NULL(priv->suspend_state)) { - DRM_ERROR("failed to back up suspend state\n"); - priv->suspend_state = NULL; - goto unlock; - } - - /* create atomic state to disable all CRTCs */ - state = drm_atomic_state_alloc(ddev); - if (IS_ERR_OR_NULL(state)) { - DRM_ERROR("failed to allocate crtc disable state\n"); - goto unlock; - } - - state->acquire_ctx = ctx; - drm_for_each_connector(conn, ddev) { - - if (!conn->state || !conn->state->crtc || - conn->dpms != DRM_MODE_DPMS_ON) - continue; - - /* force CRTC to be inactive */ - crtc_state = drm_atomic_get_crtc_state(state, - conn->state->crtc); - if (IS_ERR_OR_NULL(crtc_state)) { - DRM_ERROR("failed to get crtc %d state\n", - conn->state->crtc->base.id); - drm_atomic_state_free(state); - goto unlock; - } - crtc_state->active = false; - } + struct drm_device *ddev = dev_get_drvdata(dev); - /* commit the "disable all" state */ - ret = drm_atomic_commit(state); - if (ret < 0) { - DRM_ERROR("failed to disable crtcs, %d\n", ret); - drm_atomic_state_free(state); - } - -unlock: - drm_modeset_unlock_all(ddev); - - /* disable hot-plug polling */ drm_kms_helper_poll_disable(ddev); return 0; @@ -1999,38 +1932,8 @@ unlock: static int msm_pm_resume(struct device *dev) { - struct drm_device *ddev; - struct msm_drm_private *priv; - int ret; - - if (!dev) - return -EINVAL; - - ddev = dev_get_drvdata(dev); - if (!ddev || !ddev->dev_private) - return -EINVAL; - - priv = ddev->dev_private; - - SDE_EVT32(priv->suspend_state != NULL); - - drm_mode_config_reset(ddev); - - drm_modeset_lock_all(ddev); - - if (priv->suspend_state) { - priv->suspend_state->acquire_ctx = - ddev->mode_config.acquire_ctx; - ret = drm_atomic_commit(priv->suspend_state); - if (ret < 0) { - DRM_ERROR("failed to restore state, %d\n", ret); - drm_atomic_state_free(priv->suspend_state); - } - priv->suspend_state = NULL; - } - drm_modeset_unlock_all(ddev); + struct drm_device *ddev = dev_get_drvdata(dev); - /* enable hot-plug polling */ drm_kms_helper_poll_enable(ddev); return 0; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 25dc5f9ef561cba4a02d00e5e2c2542a1dcfd2f6..ac15f399df7d9fe75a09c7a157437dbd2ad4d508 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -144,7 +144,7 @@ enum msm_mdp_conn_property { /* blob properties, always put these first */ CONNECTOR_PROP_SDE_INFO, CONNECTOR_PROP_HDR_INFO, - CONNECTOR_PROP_HDR_CONTROL, + CONNECTOR_PROP_HDR_METADATA, /* # of blob properties */ CONNECTOR_PROP_BLOBCOUNT, @@ -158,12 +158,10 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_DST_H, CONNECTOR_PROP_PLL_DELTA, CONNECTOR_PROP_PLL_ENABLE, - CONNECTOR_PROP_HDCP_VERSION, /* enum/bitmask properties */ CONNECTOR_PROP_TOPOLOGY_NAME, CONNECTOR_PROP_TOPOLOGY_CONTROL, - CONNECTOR_PROP_LP, /* total # of properties */ CONNECTOR_PROP_COUNT @@ -239,10 +237,10 @@ struct msm_display_info { /** * struct - msm_display_kickoff_params - info for display features at kickoff - * @hdr_ctrl: HDR control info passed from userspace + * @hdr_metadata: HDR metadata info passed from userspace */ struct msm_display_kickoff_params { - struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; + struct drm_msm_ext_panel_hdr_metadata *hdr_metadata; }; /** @@ -369,9 +367,6 @@ struct msm_drm_private { struct msm_vblank_ctrl vblank_ctrl; - /* saved atomic state during system suspend */ - struct drm_atomic_state *suspend_state; - /* list of clients waiting for events */ struct list_head client_event_list; }; @@ -419,15 +414,6 @@ void __msm_fence_worker(struct work_struct *work); (_cb)->func = _func; \ } while (0) -static inline bool msm_is_suspend_state(struct drm_device *dev) -{ - if (!dev || !dev->dev_private) - return false; - - return ((struct msm_drm_private *)dev->dev_private)->suspend_state != - NULL; -} - int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 0cd458fd184b59db185646861caf3947ee7807ed..df9ddadc5c5c2825a8241af619632cbe1a93059f 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -149,6 +149,7 @@ struct msm_gem_submit { uint32_t fence; int ring; u32 flags; + bool valid; uint64_t profile_buf_iova; struct drm_msm_gem_submit_profile_buffer *profile_buf; bool secure; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index f2b6aa29b410a1a4c5a68cde72f6f77808d0480d..b73379aa9ed7bd3fac2999263638fd5ce7ca79a9 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -212,8 +212,15 @@ static int submit_validate_objects(struct msm_gpu *gpu, int contended, slow_locked = -1, i, ret = 0; retry: + submit->valid = true; + for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; + struct msm_gem_address_space *aspace; + uint64_t iova; + + aspace = (msm_obj->flags & MSM_BO_SECURE) ? + gpu->secure_aspace : submit->aspace; if (slow_locked == i) slow_locked = -1; @@ -240,6 +247,28 @@ retry: goto fail; } } + + /* if locking succeeded, pin bo: */ + ret = msm_gem_get_iova(&msm_obj->base, aspace, &iova); + + /* this would break the logic in the fail path.. there is no + * reason for this to happen, but just to be on the safe side + * let's notice if this starts happening in the future: + */ + WARN_ON(ret == -EDEADLK); + + if (ret) + goto fail; + + submit->bos[i].flags |= BO_PINNED; + + if (iova == submit->bos[i].iova) { + submit->bos[i].flags |= BO_VALID; + } else { + submit->bos[i].iova = iova; + submit->bos[i].flags &= ~BO_VALID; + submit->valid = false; + } } ww_acquire_done(&submit->ticket); @@ -268,14 +297,9 @@ fail: return ret; } -static int submit_bo(struct msm_gpu *gpu, - struct msm_gem_submit *submit, uint32_t idx, +static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, struct msm_gem_object **obj, uint64_t *iova, bool *valid) { - struct msm_gem_object *msm_obj; - struct msm_gem_address_space *aspace; - int ret; - if (idx >= submit->nr_bos) { DRM_ERROR("invalid buffer index: %u (out of %u)\n", idx, submit->nr_bos); @@ -284,39 +308,6 @@ static int submit_bo(struct msm_gpu *gpu, if (obj) *obj = submit->bos[idx].obj; - - /* Only map and pin if the caller needs either the iova or valid */ - if (!iova && !valid) - return 0; - - if (!(submit->bos[idx].flags & BO_PINNED)) { - uint64_t buf_iova; - - msm_obj = submit->bos[idx].obj; - aspace = (msm_obj->flags & MSM_BO_SECURE) ? - gpu->secure_aspace : submit->aspace; - - ret = msm_gem_get_iova(&msm_obj->base, aspace, &buf_iova); - - /* this would break the logic in the fail path.. there is no - * reason for this to happen, but just to be on the safe side - * let's notice if this starts happening in the future: - */ - WARN_ON(ret == -EDEADLK); - - if (ret) - return ret; - - submit->bos[idx].flags |= BO_PINNED; - - if (buf_iova == submit->bos[idx].iova) { - submit->bos[idx].flags |= BO_VALID; - } else { - submit->bos[idx].iova = buf_iova; - submit->bos[idx].flags &= ~BO_VALID; - } - } - if (iova) *iova = submit->bos[idx].iova; if (valid) @@ -326,10 +317,8 @@ static int submit_bo(struct msm_gpu *gpu, } /* process the reloc's and patch up the cmdstream as needed: */ -static int submit_reloc(struct msm_gpu *gpu, - struct msm_gem_submit *submit, - struct msm_gem_object *obj, uint32_t offset, - uint32_t nr_relocs, uint64_t relocs) +static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *obj, + uint32_t offset, uint32_t nr_relocs, uint64_t relocs) { uint32_t i, last_offset = 0; uint32_t *ptr; @@ -345,9 +334,6 @@ static int submit_reloc(struct msm_gpu *gpu, return -EINVAL; } - if (nr_relocs == 0) - return 0; - /* For now, just map the entire thing. Eventually we probably * to do it page-by-page, w/ kmap() if not vmap()d.. */ @@ -386,8 +372,7 @@ static int submit_reloc(struct msm_gpu *gpu, return -EINVAL; } - ret = submit_bo(gpu, submit, submit_reloc.reloc_idx, - NULL, &iova, &valid); + ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid); if (ret) return ret; @@ -497,7 +482,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out; } - ret = submit_bo(gpu, submit, submit_cmd.submit_idx, + ret = submit_bo(submit, submit_cmd.submit_idx, &msm_obj, &iova, NULL); if (ret) goto out; @@ -530,9 +515,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, + submit_cmd.submit_offset; } - ret = submit_reloc(gpu, submit, msm_obj, - submit_cmd.submit_offset, submit_cmd.nr_relocs, - submit_cmd.relocs); + if (submit->valid) + continue; + + ret = submit_reloc(submit, msm_obj, submit_cmd.submit_offset, + submit_cmd.nr_relocs, submit_cmd.relocs); if (ret) goto out; } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 7c109fdab5453d641a6947d1c626d86d7e68f6d8..8073898e427576659c67782a5179d2628d910d57 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -863,14 +863,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, gpu->dev = drm; gpu->funcs = funcs; gpu->name = name; - /* - * Set the inactive flag to false, so that when the retire worker - * kicks in from the init path, it knows that it has to turn off the - * clocks. This should be fine to do since this is the init sequence - * and we have an init_lock in msm_open() to protect against bad things - * from happening. - */ - gpu->inactive = false; + gpu->inactive = true; INIT_LIST_HEAD(&gpu->active_list); INIT_WORK(&gpu->retire_work, retire_worker); @@ -904,7 +897,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, ret = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, IRQF_TRIGGER_HIGH, gpu->name, gpu); if (ret) { - gpu->irq = ret; dev_err(drm->dev, "failed to request IRQ%u: %d\n", gpu->irq, ret); goto fail; } @@ -1015,11 +1007,6 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) WARN_ON(!list_empty(&gpu->active_list)); - if (gpu->irq >= 0) { - disable_irq(gpu->irq); - devm_free_irq(&pdev->dev, gpu->irq, gpu); - } - bs_fini(gpu); for (i = 0; i < ARRAY_SIZE(gpu->rb); i++) @@ -1035,22 +1022,4 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) msm_gpu_destroy_address_space(gpu->aspace); msm_gpu_destroy_address_space(gpu->secure_aspace); - - if (gpu->gpu_reg) - devm_regulator_put(gpu->gpu_reg); - - if (gpu->gpu_cx) - devm_regulator_put(gpu->gpu_cx); - - if (gpu->ebi1_clk) - devm_clk_put(&pdev->dev, gpu->ebi1_clk); - - for (i = gpu->nr_clocks - 1; i >= 0; i--) - if (gpu->grp_clks[i]) - devm_clk_put(&pdev->dev, gpu->grp_clks[i]); - - devm_kfree(&pdev->dev, gpu->grp_clks); - - if (gpu->mmio) - devm_iounmap(&pdev->dev, gpu->mmio); } diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index ed0ba928f170a04df7cbe72c59c7e6db60133ec0..2ab50919f514976cb7e3df7dc80cc9f6278ab666 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -34,24 +34,6 @@ #define MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS (1<<0) /* Transition to new mode requires a wait-for-vblank before the modeset */ #define MSM_MODE_FLAG_VBLANK_PRE_MODESET (1<<1) -/* - * We need setting some flags in bridge, and using them in encoder. Add them in - * private_flags would be better for use. DRM_MODE_FLAG_SUPPORTS_RGB/YUV are - * flags that indicating the SINK supported color formats read from EDID. While, - * these flags defined here indicate the best color/bit depth foramt we choosed - * that would be better for display. For example the best mode display like: - * RGB+RGB_DC,YUV+YUV_DC, RGB,YUV. And we could not set RGB and YUV format at - * the same time. And also RGB_DC only set when RGB format is set,the same for - * YUV_DC. - */ -/* Enable RGB444 30 bit deep color */ -#define MSM_MODE_FLAG_RGB444_DC_ENABLE (1<<2) -/* Enable YUV420 30 bit deep color */ -#define MSM_MODE_FLAG_YUV420_DC_ENABLE (1<<3) -/* Choose RGB444 format to display */ -#define MSM_MODE_FLAG_COLOR_FORMAT_RGB444 (1<<4) -/* Choose YUV420 format to display */ -#define MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420 (1<<5) /* As there are different display controller blocks depending on the * snapdragon version, the kms support is split out and the appropriate diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index cd3a710f8f27e4207b1a7974d5bc0675fbd31916..8148d3e9e850f9e40967670d9f9b69aa0e12d1d0 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -46,8 +46,6 @@ struct msm_mmu_funcs { void (*destroy)(struct msm_mmu *mmu); void (*enable)(struct msm_mmu *mmu); void (*disable)(struct msm_mmu *mmu); - int (*set_property)(struct msm_mmu *mmu, - enum iommu_attr attr, void *data); }; struct msm_mmu { diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index 4247243055b679fbab10a89eb0a3b5dd18f2f9aa..eb68eb977aa72c5b74b7a61c977d22802ab14522 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -170,36 +170,12 @@ static void msm_smmu_destroy(struct msm_mmu *mmu) kfree(smmu); } -/* user can call this API to set the attribute of smmu*/ -static int msm_smmu_set_property(struct msm_mmu *mmu, - enum iommu_attr attr, void *data) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - struct iommu_domain *domain; - int ret = 0; - - if (!client) - return -EINVAL; - - domain = client->mmu_mapping->domain; - if (!domain) - return -EINVAL; - - ret = iommu_domain_set_attr(domain, attr, data); - if (ret) - DRM_ERROR("set domain attribute failed\n"); - - return ret; -} - static const struct msm_mmu_funcs funcs = { .attach = msm_smmu_attach, .detach = msm_smmu_detach, .map = msm_smmu_map, .unmap = msm_smmu_unmap, .destroy = msm_smmu_destroy, - .set_property = msm_smmu_set_property, }; static struct msm_smmu_domain msm_smmu_domains[MSM_SMMU_DOMAIN_MAX] = { diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 8d15fd2f9cf7c4918532c978f68e55f4f27a0df1..76e6e4ef6e7de07463a07ba2416217de954c1343 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. */ -#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#define pr_fmt(fmt) "sde-drm:[%s] " fmt, __func__ #include "msm_drv.h" #include "sde_kms.h" @@ -38,13 +38,6 @@ static const struct drm_prop_enum_list e_topology_control[] = { {SDE_RM_TOPCTL_PPSPLIT, "ppsplit"} }; -static const struct drm_prop_enum_list e_power_mode[] = { - {SDE_MODE_DPMS_ON, "ON"}, - {SDE_MODE_DPMS_LP1, "LP1"}, - {SDE_MODE_DPMS_LP2, "LP2"}, - {SDE_MODE_DPMS_OFF, "OFF"}, -}; - int sde_connector_get_info(struct drm_connector *connector, struct msm_display_info *info) { @@ -90,57 +83,13 @@ int sde_connector_pre_kickoff(struct drm_connector *connector) if (!c_conn->ops.pre_kickoff) return 0; - params.hdr_ctrl = &c_state->hdr_ctrl; + params.hdr_metadata = &c_state->hdr_meta; rc = c_conn->ops.pre_kickoff(connector, c_conn->display, ¶ms); return rc; } -enum sde_csc_type sde_connector_get_csc_type(struct drm_connector *conn) -{ - struct sde_connector *c_conn; - - if (!conn) { - SDE_ERROR("invalid argument\n"); - return -EINVAL; - } - - c_conn = to_sde_connector(conn); - - if (!c_conn->display) { - SDE_ERROR("invalid argument\n"); - return -EINVAL; - } - - if (!c_conn->ops.get_csc_type) - return SDE_CSC_RGB2YUV_601L; - - return c_conn->ops.get_csc_type(conn, c_conn->display); -} - -bool sde_connector_mode_needs_full_range(struct drm_connector *connector) -{ - struct sde_connector *c_conn; - - if (!connector) { - SDE_ERROR("invalid argument\n"); - return false; - } - - c_conn = to_sde_connector(connector); - - if (!c_conn->display) { - SDE_ERROR("invalid argument\n"); - return false; - } - - if (!c_conn->ops.mode_needs_full_range) - return false; - - return c_conn->ops.mode_needs_full_range(c_conn->display); -} - static void sde_connector_destroy(struct drm_connector *connector) { struct sde_connector *c_conn; @@ -162,7 +111,6 @@ static void sde_connector_destroy(struct drm_connector *connector) msm_property_destroy(&c_conn->property_info); drm_connector_unregister(connector); - mutex_destroy(&c_conn->lock); sde_fence_deinit(&c_conn->retire_fence); drm_connector_cleanup(connector); kfree(c_conn); @@ -299,7 +247,6 @@ static int _sde_connector_set_hdr_info( void *usr_ptr) { struct drm_connector *connector; - struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl; struct drm_msm_ext_panel_hdr_metadata *hdr_meta; int i; @@ -315,26 +262,21 @@ static int _sde_connector_set_hdr_info( return -ENOTSUPP; } - memset(&c_state->hdr_ctrl, 0, sizeof(c_state->hdr_ctrl)); + memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); if (!usr_ptr) { - SDE_DEBUG_CONN(c_conn, "hdr control cleared\n"); + SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n"); return 0; } - if (copy_from_user(&c_state->hdr_ctrl, + if (copy_from_user(&c_state->hdr_meta, (void __user *)usr_ptr, - sizeof(*hdr_ctrl))) { - SDE_ERROR_CONN(c_conn, "failed to copy hdr control\n"); + sizeof(*hdr_meta))) { + SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n"); return -EFAULT; } - hdr_ctrl = &c_state->hdr_ctrl; - - SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", - hdr_ctrl->hdr_state); - - hdr_meta = &hdr_ctrl->hdr_meta; + hdr_meta = &c_state->hdr_meta; SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", hdr_meta->hdr_supported); @@ -361,56 +303,6 @@ static int _sde_connector_set_hdr_info( return 0; } -static int _sde_connector_update_power_locked(struct sde_connector *c_conn) -{ - struct drm_connector *connector; - void *display; - int (*set_power)(struct drm_connector *, int, void *); - int mode, rc = 0; - - if (!c_conn) - return -EINVAL; - connector = &c_conn->base; - - mode = c_conn->lp_mode; - if (c_conn->dpms_mode != DRM_MODE_DPMS_ON) - mode = SDE_MODE_DPMS_OFF; - switch (c_conn->dpms_mode) { - case DRM_MODE_DPMS_ON: - mode = c_conn->lp_mode; - break; - case DRM_MODE_DPMS_STANDBY: - mode = SDE_MODE_DPMS_STANDBY; - break; - case DRM_MODE_DPMS_SUSPEND: - mode = SDE_MODE_DPMS_SUSPEND; - break; - case DRM_MODE_DPMS_OFF: - mode = SDE_MODE_DPMS_OFF; - break; - default: - mode = c_conn->lp_mode; - SDE_ERROR("conn %d dpms set to unrecognized mode %d\n", - connector->base.id, mode); - break; - } - - SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id, - c_conn->dpms_mode, c_conn->lp_mode, mode); - - if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) { - display = c_conn->display; - set_power = c_conn->ops.set_power; - - mutex_unlock(&c_conn->lock); - rc = set_power(connector, mode, display); - mutex_lock(&c_conn->lock); - } - c_conn->last_panel_power_mode = mode; - - return rc; -} - static int sde_connector_atomic_set_property(struct drm_connector *connector, struct drm_connector_state *state, struct drm_property *property, @@ -437,8 +329,8 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, /* connector-specific property handling */ idx = msm_property_index(&c_conn->property_info, property); - switch (idx) { - case CONNECTOR_PROP_OUT_FB: + + if (idx == CONNECTOR_PROP_OUT_FB) { /* clear old fb, if present */ if (c_state->out_fb) _sde_connector_destroy_fb(c_conn, c_state); @@ -462,23 +354,15 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, if (rc) SDE_ERROR("prep fb failed, %d\n", rc); } - break; - case CONNECTOR_PROP_TOPOLOGY_CONTROL: + } + + if (idx == CONNECTOR_PROP_TOPOLOGY_CONTROL) { rc = sde_rm_check_property_topctl(val); if (rc) SDE_ERROR("invalid topology_control: 0x%llX\n", val); - break; - case CONNECTOR_PROP_LP: - mutex_lock(&c_conn->lock); - c_conn->lp_mode = val; - _sde_connector_update_power_locked(c_conn); - mutex_unlock(&c_conn->lock); - break; - default: - break; - } - - if (idx == CONNECTOR_PROP_HDR_CONTROL) { + } + + if (idx == CONNECTOR_PROP_HDR_METADATA) { rc = _sde_connector_set_hdr_info(c_conn, c_state, (void *)val); if (rc) SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc); @@ -576,60 +460,6 @@ void sde_connector_complete_commit(struct drm_connector *connector) sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0); } -static int sde_connector_dpms(struct drm_connector *connector, - int mode) -{ - struct sde_connector *c_conn; - - if (!connector) { - SDE_ERROR("invalid connector\n"); - return -EINVAL; - } - c_conn = to_sde_connector(connector); - - /* validate incoming dpms request */ - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - SDE_DEBUG("conn %d dpms set to %d\n", - connector->base.id, mode); - break; - default: - SDE_ERROR("conn %d dpms set to unrecognized mode %d\n", - connector->base.id, mode); - break; - } - - mutex_lock(&c_conn->lock); - c_conn->dpms_mode = mode; - _sde_connector_update_power_locked(c_conn); - mutex_unlock(&c_conn->lock); - - /* use helper for boilerplate handling */ - return drm_atomic_helper_connector_dpms(connector, mode); -} - -int sde_connector_get_dpms(struct drm_connector *connector) -{ - struct sde_connector *c_conn; - int rc; - - if (!connector) { - SDE_DEBUG("invalid connector\n"); - return DRM_MODE_DPMS_OFF; - } - - c_conn = to_sde_connector(connector); - - mutex_lock(&c_conn->lock); - rc = c_conn->dpms_mode; - mutex_unlock(&c_conn->lock); - - return rc; -} - static void sde_connector_update_hdr_props(struct drm_connector *connector) { struct sde_connector *c_conn = to_sde_connector(connector); @@ -678,7 +508,7 @@ sde_connector_detect(struct drm_connector *connector, bool force) } static const struct drm_connector_funcs sde_connector_ops = { - .dpms = sde_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .reset = sde_connector_atomic_reset, .detect = sde_connector_detect, .destroy = sde_connector_destroy, @@ -768,7 +598,6 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, struct sde_kms *sde_kms; struct sde_kms_info *info; struct sde_connector *c_conn = NULL; - struct sde_splash_info *sinfo; int rc; if (!dev || !dev->dev_private || !encoder) { @@ -801,11 +630,6 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, c_conn->panel = panel; c_conn->display = display; - c_conn->dpms_mode = DRM_MODE_DPMS_ON; - c_conn->lp_mode = 0; - c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON; - - sde_kms = to_sde_kms(priv->kms); if (sde_kms->vbif[VBIF_NRT]) { c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = @@ -839,8 +663,6 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, goto error_cleanup_conn; } - mutex_init(&c_conn->lock); - rc = drm_connector_register(&c_conn->base); if (rc) { SDE_ERROR("failed to register drm connector, %d\n", rc); @@ -896,8 +718,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, } msm_property_install_volatile_range(&c_conn->property_info, - "hdr_control", 0x0, 0, ~0, 0, - CONNECTOR_PROP_HDR_CONTROL); + "hdr_metadata", 0x0, 0, ~0, 0, + CONNECTOR_PROP_HDR_METADATA); msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE", 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE); @@ -910,10 +732,6 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, "PLL_ENABLE", 0x0, 0, 1, 0, CONNECTOR_PROP_PLL_ENABLE); - msm_property_install_volatile_range(&c_conn->property_info, - "HDCP_VERSION", 0x0, 0, U8_MAX, 0, - CONNECTOR_PROP_HDCP_VERSION); - /* enum/bitmask properties */ msm_property_install_enum(&c_conn->property_info, "topology_name", DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, @@ -924,11 +742,6 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, ARRAY_SIZE(e_topology_control), CONNECTOR_PROP_TOPOLOGY_CONTROL, 0); - msm_property_install_enum(&c_conn->property_info, "LP", - 0, 0, e_power_mode, - ARRAY_SIZE(e_power_mode), - CONNECTOR_PROP_LP, 0); - rc = msm_property_install_get_status(&c_conn->property_info); if (rc) { SDE_ERROR("failed to create one or more properties\n"); @@ -938,10 +751,6 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, SDE_DEBUG("connector %d attach encoder %d\n", c_conn->base.base.id, encoder->base.id); - sinfo = &sde_kms->splash_info; - if (sinfo && sinfo->handoff) - sde_splash_setup_connector_count(sinfo, connector_type); - priv->connectors[priv->num_connectors++] = &c_conn->base; return &c_conn->base; @@ -955,7 +764,6 @@ error_destroy_property: error_unregister_conn: drm_connector_unregister(&c_conn->base); error_cleanup_fence: - mutex_destroy(&c_conn->lock); sde_fence_deinit(&c_conn->retire_fence); error_cleanup_conn: drm_connector_cleanup(&c_conn->base); diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index f9b8c3966d74899fbe4d9000a27442a6033d7395..19e2b8a3e41c65105545127c12ee75d711cfb1be 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -135,38 +135,6 @@ struct sde_connector_ops { int (*pre_kickoff)(struct drm_connector *connector, void *display, struct msm_display_kickoff_params *params); - - /** - * mode_needs_full_range - does the mode need full range - * quantization - * @display: Pointer to private display structure - * Returns: true or false based on whether full range is needed - */ - bool (*mode_needs_full_range)(void *display); - - /** - * get_csc_type - returns the CSC type to be used - * by the CDM block based on HDR state - * @connector: Pointer to drm connector structure - * @display: Pointer to private display structure - * Returns: type of CSC matrix to be used - */ - enum sde_csc_type (*get_csc_type)(struct drm_connector *connector, - void *display); - - /** - * set_power - update dpms setting - * @connector: Pointer to drm connector structure - * @power_mode: One of the following, - * SDE_MODE_DPMS_ON - * SDE_MODE_DPMS_LP1 - * SDE_MODE_DPMS_LP2 - * SDE_MODE_DPMS_OFF - * @display: Pointer to private display structure - * Returns: Zero on success - */ - int (*set_power)(struct drm_connector *connector, - int power_mode, void *display); }; /** @@ -179,12 +147,8 @@ struct sde_connector_ops { * @mmu_secure: MMU id for secure buffers * @mmu_unsecure: MMU id for unsecure buffers * @name: ASCII name of connector - * @lock: Mutex lock object for this structure * @retire_fence: Retire fence reference * @ops: Local callback function pointer table - * @dpms_mode: DPMS property setting from user space - * @lp_mode: LP property setting from user space - * @last_panel_power_mode: Last consolidated dpms/lp mode setting * @property_info: Private structure for generic property handling * @property_data: Array of private data for generic property handling * @blob_caps: Pointer to blob structure for 'capabilities' property @@ -203,12 +167,8 @@ struct sde_connector { char name[SDE_CONNECTOR_NAME_SIZE]; - struct mutex lock; struct sde_fence retire_fence; struct sde_connector_ops ops; - int dpms_mode; - int lp_mode; - int last_panel_power_mode; struct msm_property_info property_info; struct msm_property_data property_data[CONNECTOR_PROP_COUNT]; @@ -261,14 +221,14 @@ struct sde_connector { * @out_fb: Pointer to output frame buffer, if applicable * @aspace: Address space for accessing frame buffer objects, if applicable * @property_values: Local cache of current connector property values - * @hdr_ctrl: HDR control info passed from userspace + * @hdr_meta: HDR metadata info passed from userspace */ struct sde_connector_state { struct drm_connector_state base; struct drm_framebuffer *out_fb; struct msm_gem_address_space *aspace; uint64_t property_values[CONNECTOR_PROP_COUNT]; - struct drm_msm_ext_panel_hdr_ctrl hdr_ctrl; + struct drm_msm_ext_panel_hdr_metadata hdr_meta; }; /** @@ -367,28 +327,5 @@ int sde_connector_get_info(struct drm_connector *connector, */ int sde_connector_pre_kickoff(struct drm_connector *connector); -/** - * sde_connector_mode_needs_full_range - query quantization type - * for the connector mode - * @connector: Pointer to drm connector object - * Returns: true OR false based on connector mode - */ -bool sde_connector_mode_needs_full_range(struct drm_connector *connector); - -/** - * sde_connector_get_csc_type - query csc type - * to be used for the connector - * @connector: Pointer to drm connector object - * Returns: csc type based on connector HDR state - */ -enum sde_csc_type sde_connector_get_csc_type(struct drm_connector *conn); - -/** - * sde_connector_get_dpms - query dpms setting - * @connector: Pointer to drm connector structure - * Returns: Current DPMS setting for connector - */ -int sde_connector_get_dpms(struct drm_connector *connector); - #endif /* _SDE_CONNECTOR_H_ */ diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 870b4c6b74aba5fa100355ef5885a5ed7d59b779..5a49a1beee49711150f340d49d41c98a12578f0a 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -57,17 +57,7 @@ static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) { - struct msm_drm_private *priv; - - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { - SDE_ERROR("invalid crtc\n"); - return NULL; - } - priv = crtc->dev->dev_private; - if (!priv || !priv->kms) { - SDE_ERROR("invalid kms\n"); - return NULL; - } + struct msm_drm_private *priv = crtc->dev->dev_private; return to_sde_kms(priv->kms); } @@ -87,10 +77,10 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) sde_cp_crtc_destroy_properties(crtc); debugfs_remove_recursive(sde_crtc->debugfs_root); + mutex_destroy(&sde_crtc->crtc_lock); sde_fence_deinit(&sde_crtc->output_fence); drm_crtc_cleanup(crtc); - mutex_destroy(&sde_crtc->crtc_lock); kfree(sde_crtc); } @@ -600,22 +590,14 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc, { struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; - struct drm_connector *conn; - struct drm_device *dev; - struct msm_drm_private *priv; - struct sde_kms *sde_kms; int i; - if (!crtc || !crtc->state || !crtc->dev) { + if (!crtc || !crtc->state) { SDE_ERROR("invalid crtc\n"); return; } - dev = crtc->dev; - priv = dev->dev_private; - sde_crtc = to_sde_crtc(crtc); - sde_kms = _sde_crtc_get_kms(crtc); cstate = to_sde_crtc_state(crtc->state); SDE_EVT32(DRMID(crtc)); @@ -624,20 +606,6 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc, for (i = 0; i < cstate->num_connectors; ++i) sde_connector_complete_commit(cstate->connectors[i]); - - if (!sde_kms->splash_info.handoff && - sde_kms->splash_info.lk_is_exited) { - mutex_lock(&dev->mode_config.mutex); - drm_for_each_connector(conn, crtc->dev) { - if (conn->state->crtc != crtc) - continue; - - sde_splash_clean_up_free_resource(priv->kms, - &priv->phandle, - conn->connector_type); - } - mutex_unlock(&dev->mode_config.mutex); - } } /** @@ -932,15 +900,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc) sde_kms = _sde_crtc_get_kms(crtc); priv = sde_kms->dev->dev_private; - /* - * If no mixers has been allocated in sde_crtc_atomic_check(), - * it means we are trying to start a CRTC whose state is disabled: - * nothing else needs to be done. - */ - if (unlikely(!sde_crtc->num_mixers)) - return; - - SDE_ATRACE_BEGIN("crtc_commit"); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc != crtc) @@ -981,120 +940,6 @@ end: return; } -/** - * _sde_crtc_vblank_enable_nolock - update power resource and vblank request - * @sde_crtc: Pointer to sde crtc structure - * @enable: Whether to enable/disable vblanks - * - * @Return: error code - */ -static int _sde_crtc_vblank_enable_no_lock( - struct sde_crtc *sde_crtc, bool enable) -{ - struct drm_device *dev; - struct drm_crtc *crtc; - struct drm_encoder *enc; - struct msm_drm_private *priv; - struct sde_kms *sde_kms; - int ret = 0; - - if (!sde_crtc) { - SDE_ERROR("invalid crtc\n"); - return -EINVAL; - } - - crtc = &sde_crtc->base; - dev = crtc->dev; - priv = dev->dev_private; - - if (!priv->kms) { - SDE_ERROR("invalid kms\n"); - return -EINVAL; - } - sde_kms = to_sde_kms(priv->kms); - - if (enable) { - ret = sde_power_resource_enable(&priv->phandle, - sde_kms->core_client, true); - if (ret) - return ret; - - list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { - if (enc->crtc != crtc) - continue; - - SDE_EVT32(DRMID(crtc), DRMID(enc), enable); - - sde_encoder_register_vblank_callback(enc, - sde_crtc_vblank_cb, (void *)crtc); - } - } else { - list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { - if (enc->crtc != crtc) - continue; - - SDE_EVT32(DRMID(crtc), DRMID(enc), enable); - - sde_encoder_register_vblank_callback(enc, NULL, NULL); - } - ret = sde_power_resource_enable(&priv->phandle, - sde_kms->core_client, false); - } - - return ret; -} - -/** - * _sde_crtc_set_suspend - notify crtc of suspend enable/disable - * @crtc: Pointer to drm crtc object - * @enable: true to enable suspend, false to indicate resume - */ -static void _sde_crtc_set_suspend(struct drm_crtc *crtc, bool enable) -{ - struct sde_crtc *sde_crtc; - struct msm_drm_private *priv; - struct sde_kms *sde_kms; - - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { - SDE_ERROR("invalid crtc\n"); - return; - } - sde_crtc = to_sde_crtc(crtc); - priv = crtc->dev->dev_private; - - if (!priv->kms) { - SDE_ERROR("invalid crtc kms\n"); - return; - } - sde_kms = to_sde_kms(priv->kms); - - SDE_DEBUG("crtc%d suspend = %d\n", crtc->base.id, enable); - - mutex_lock(&sde_crtc->crtc_lock); - - /* - * Update CP on suspend/resume transitions - */ - if (enable && !sde_crtc->suspend) - sde_cp_crtc_suspend(crtc); - else if (!enable && sde_crtc->suspend) - sde_cp_crtc_resume(crtc); - - /* - * If the vblank refcount != 0, release a power reference on suspend - * and take it back during resume (if it is still != 0). - */ - if (sde_crtc->suspend == enable) - SDE_DEBUG("crtc%d suspend already set to %d, ignoring update\n", - crtc->base.id, enable); - else if (sde_crtc->enabled && sde_crtc->vblank_requested) - _sde_crtc_vblank_enable_no_lock(sde_crtc, !enable); - - sde_crtc->suspend = enable; - - mutex_unlock(&sde_crtc->crtc_lock); -} - /** * sde_crtc_duplicate_state - state duplicate hook * @crtc: Pointer to drm crtc structure @@ -1145,10 +990,6 @@ static void sde_crtc_reset(struct drm_crtc *crtc) return; } - /* revert suspend actions, if necessary */ - if (msm_is_suspend_state(crtc->dev)) - _sde_crtc_set_suspend(crtc, false); - /* remove previous state, if present */ if (crtc->state) { sde_crtc_destroy_state(crtc, crtc->state); @@ -1174,43 +1015,37 @@ static void sde_crtc_reset(struct drm_crtc *crtc) static void sde_crtc_disable(struct drm_crtc *crtc) { - struct drm_encoder *encoder; + struct msm_drm_private *priv; struct sde_crtc *sde_crtc; + struct drm_encoder *encoder; struct sde_kms *sde_kms; - struct msm_drm_private *priv; - int ret = 0; - if (!crtc || !crtc->dev || !crtc->state) { + if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } sde_crtc = to_sde_crtc(crtc); sde_kms = _sde_crtc_get_kms(crtc); - if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { - SDE_ERROR("invalid kms handle\n"); - return; - } priv = sde_kms->dev->dev_private; SDE_DEBUG("crtc%d\n", crtc->base.id); - if (msm_is_suspend_state(crtc->dev)) - _sde_crtc_set_suspend(crtc, true); - mutex_lock(&sde_crtc->crtc_lock); - SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend, - sde_crtc->vblank_requested); + SDE_EVT32(DRMID(crtc)); - if (sde_crtc->enabled && !sde_crtc->suspend && - sde_crtc->vblank_requested) { - ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, false); - if (ret) - SDE_ERROR("%s vblank enable failed: %d\n", - sde_crtc->name, ret); + if (atomic_read(&sde_crtc->vblank_refcount)) { + SDE_ERROR("crtc%d invalid vblank refcount\n", + crtc->base.id); + SDE_EVT32(DRMID(crtc)); + drm_for_each_encoder(encoder, crtc->dev) { + if (encoder->crtc != crtc) + continue; + sde_encoder_register_vblank_callback(encoder, NULL, + NULL); + } + atomic_set(&sde_crtc->vblank_refcount, 0); } - sde_crtc->enabled = false; - if (atomic_read(&sde_crtc->frame_pending)) { /* release bandwidth and other resources */ SDE_ERROR("crtc%d invalid frame pending\n", @@ -1245,7 +1080,6 @@ static void sde_crtc_enable(struct drm_crtc *crtc) struct sde_hw_mixer_cfg cfg; struct drm_encoder *encoder; int i; - int ret = 0; if (!crtc) { SDE_ERROR("invalid crtc\n"); @@ -1274,19 +1108,6 @@ static void sde_crtc_enable(struct drm_crtc *crtc) sde_crtc_request_flip_cb, (void *)crtc); } - mutex_lock(&sde_crtc->crtc_lock); - SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend, - sde_crtc->vblank_requested); - if (!sde_crtc->enabled && !sde_crtc->suspend && - sde_crtc->vblank_requested) { - ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, true); - if (ret) - SDE_ERROR("%s vblank enable failed: %d\n", - sde_crtc->name, ret); - } - sde_crtc->enabled = true; - mutex_unlock(&sde_crtc->crtc_lock); - for (i = 0; i < sde_crtc->num_mixers; i++) { lm = mixer[i].hw_lm; cfg.out_width = sde_crtc_mixer_width(sde_crtc, mode); @@ -1351,10 +1172,6 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, mode = &state->adjusted_mode; SDE_DEBUG("%s: check", sde_crtc->name); - /* force a full mode set if active state changed */ - if (state->active_changed) - state->mode_changed = true; - mixer_width = sde_crtc_mixer_width(sde_crtc, mode); /* get plane state for all drm planes associated with crtc state */ @@ -1445,27 +1262,38 @@ end: int sde_crtc_vblank(struct drm_crtc *crtc, bool en) { - struct sde_crtc *sde_crtc; - int ret; + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct drm_encoder *encoder; + struct drm_device *dev = crtc->dev; - if (!crtc) { - SDE_ERROR("invalid crtc\n"); + if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) { + SDE_DEBUG("crtc%d vblank enable\n", crtc->base.id); + } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) { + SDE_ERROR("crtc%d invalid vblank disable\n", crtc->base.id); return -EINVAL; + } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) { + SDE_DEBUG("crtc%d vblank disable\n", crtc->base.id); + } else { + SDE_DEBUG("crtc%d vblank %s refcount:%d\n", + crtc->base.id, + en ? "enable" : "disable", + atomic_read(&sde_crtc->vblank_refcount)); + return 0; } - sde_crtc = to_sde_crtc(crtc); - mutex_lock(&sde_crtc->crtc_lock); - SDE_EVT32(DRMID(&sde_crtc->base), en, sde_crtc->enabled, - sde_crtc->suspend, sde_crtc->vblank_requested); - if (sde_crtc->enabled && !sde_crtc->suspend) { - ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, en); - if (ret) - SDE_ERROR("%s vblank enable failed: %d\n", - sde_crtc->name, ret); - } + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; - sde_crtc->vblank_requested = en; - mutex_unlock(&sde_crtc->crtc_lock); + SDE_EVT32(DRMID(crtc), en); + + if (en) + sde_encoder_register_vblank_callback(encoder, + sde_crtc_vblank_cb, (void *)crtc); + else + sde_encoder_register_vblank_callback(encoder, NULL, + NULL); + } return 0; } @@ -1557,7 +1385,6 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, if (catalog->qseed_type == SDE_SSPP_SCALER_QSEED3) sde_kms_info_add_keystr(info, "qseed_type", "qseed3"); sde_kms_info_add_keyint(info, "has_src_split", catalog->has_src_split); - sde_kms_info_add_keyint(info, "has_hdr", catalog->has_hdr); if (catalog->perf.max_bw_low) sde_kms_info_add_keyint(info, "max_bandwidth_low", catalog->perf.max_bw_low); @@ -1568,7 +1395,7 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, sde_kms_info_add_keyint(info, "max_mdp_clk", sde_kms->perf.max_core_clk_rate); msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info, - info->data, SDE_KMS_INFO_DATALEN(info), CRTC_PROP_INFO); + info->data, info->len, CRTC_PROP_INFO); kfree(info); } @@ -1780,7 +1607,8 @@ static int _sde_debugfs_status_show(struct seq_file *s, void *data) sde_crtc->vblank_cb_time = ktime_set(0, 0); } - seq_printf(s, "vblank_enable:%d\n", sde_crtc->vblank_requested); + seq_printf(s, "vblank_refcount:%d\n", + atomic_read(&sde_crtc->vblank_refcount)); mutex_unlock(&sde_crtc->crtc_lock); @@ -1908,8 +1736,8 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, crtc = &sde_crtc->base; crtc->dev = dev; + atomic_set(&sde_crtc->vblank_refcount, 0); - mutex_init(&sde_crtc->crtc_lock); spin_lock_init(&sde_crtc->spin_lock); atomic_set(&sde_crtc->frame_pending, 0); @@ -1931,6 +1759,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, snprintf(sde_crtc->name, SDE_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); /* initialize output fence support */ + mutex_init(&sde_crtc->crtc_lock); sde_fence_init(&sde_crtc->output_fence, sde_crtc->name, crtc->base.id); /* initialize debugfs support */ diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 0eed61580cd80fb065b19b8f3aeb1263d4d16679..aaa815c76c4e7c6ffc9683eb7dc82431f721c581 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -81,11 +81,7 @@ struct sde_crtc_frame_event { * @debugfs_root : Parent of debugfs node * @vblank_cb_count : count of vblank callback since last reset * @vblank_cb_time : ktime at vblank count reset - * @vblank_requested : whether the user has requested vblank events - * @suspend : whether or not a suspend operation is in progress - * @enabled : whether the SDE CRTC is currently enabled. updated in the - * commit-thread, not state-swap time which is earlier, so - * safe to make decisions on during VBLANK on/off work + * @vblank_refcount : reference count for vblank enable request * @feature_list : list of color processing features supported on a crtc * @active_list : list of color processing features are active * @dirty_list : list of color processing features are dirty @@ -120,9 +116,7 @@ struct sde_crtc { u32 vblank_cb_count; ktime_t vblank_cb_time; - bool vblank_requested; - bool suspend; - bool enabled; + atomic_t vblank_refcount; struct list_head feature_list; struct list_head active_list; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 23fb79241d84afa033fe958524f7a6934a9dfac8..29444a83cf02f5c02382d0c37de28c4f31d36f00 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -55,69 +55,6 @@ #define MAX_CHANNELS_PER_ENC 2 -/* rgb to yuv color space conversion matrix */ -static struct sde_csc_cfg sde_csc_10bit_convert[SDE_MAX_CSC] = { - [SDE_CSC_RGB2YUV_601L] = { - { - TO_S15D16(0x0083), TO_S15D16(0x0102), TO_S15D16(0x0032), - TO_S15D16(0xffb4), TO_S15D16(0xff6b), TO_S15D16(0x00e1), - TO_S15D16(0x00e1), TO_S15D16(0xff44), TO_S15D16(0xffdb), - }, - { 0x0, 0x0, 0x0,}, - { 0x0040, 0x0200, 0x0200,}, - { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, - { 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,}, - }, - - [SDE_CSC_RGB2YUV_601FR] = { - { - TO_S15D16(0x0099), TO_S15D16(0x012d), TO_S15D16(0x003a), - TO_S15D16(0xffaa), TO_S15D16(0xff56), TO_S15D16(0x0100), - TO_S15D16(0x0100), TO_S15D16(0xff2a), TO_S15D16(0xffd6), - }, - { 0x0, 0x0, 0x0,}, - { 0x0000, 0x0200, 0x0200,}, - { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, - { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, - }, - - [SDE_CSC_RGB2YUV_709L] = { - { - TO_S15D16(0x005d), TO_S15D16(0x013a), TO_S15D16(0x0020), - TO_S15D16(0xffcc), TO_S15D16(0xff53), TO_S15D16(0x00e1), - TO_S15D16(0x00e1), TO_S15D16(0xff34), TO_S15D16(0xffeb), - }, - { 0x0, 0x0, 0x0,}, - { 0x0040, 0x0200, 0x0200,}, - { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, - { 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,}, - }, - - [SDE_CSC_RGB2YUV_2020L] = { - { - TO_S15D16(0x0073), TO_S15D16(0x0129), TO_S15D16(0x001a), - TO_S15D16(0xffc1), TO_S15D16(0xff5e), TO_S15D16(0x00e0), - TO_S15D16(0x00e0), TO_S15D16(0xff32), TO_S15D16(0xffee), - }, - { 0x0, 0x0, 0x0,}, - { 0x0040, 0x0200, 0x0200,}, - { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, - { 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,}, - }, - - [SDE_CSC_RGB2YUV_2020FR] = { - { - TO_S15D16(0x0086), TO_S15D16(0x015b), TO_S15D16(0x001e), - TO_S15D16(0xffb9), TO_S15D16(0xff47), TO_S15D16(0x0100), - TO_S15D16(0x0100), TO_S15D16(0xff15), TO_S15D16(0xffeb), - }, - { 0x0, 0x0, 0x0,}, - { 0x0, 0x0200, 0x0200,}, - { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, - { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,}, - }, -}; - /** * struct sde_encoder_virt - virtual encoder. Container of one or more physical * encoders. Virtual encoder manages one "logical" display. Physical @@ -862,12 +799,7 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc; struct sde_encoder_phys *phys; - struct drm_connector *conn_mas = NULL; unsigned int i; - enum sde_csc_type conn_csc; - struct drm_display_mode *mode; - struct sde_hw_cdm *hw_cdm; - int mode_is_yuv = 0; int rc; if (!drm_enc) { @@ -887,46 +819,11 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) } if (sde_enc->cur_master && sde_enc->cur_master->connector) { - conn_mas = sde_enc->cur_master->connector; - rc = sde_connector_pre_kickoff(conn_mas); + rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector); if (rc) - SDE_ERROR_ENC(sde_enc, - "kickoff conn%d failed rc %d\n", - conn_mas->base.id, - rc); - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - phys = sde_enc->phys_encs[i]; - if (phys) { - mode = &phys->cached_mode; - mode_is_yuv = (mode->private_flags & - MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420); - } - /** - * Check the CSC matrix type to which the - * CDM CSC matrix should be updated to based - * on the connector HDR state - */ - conn_csc = sde_connector_get_csc_type(conn_mas); - if (phys && mode_is_yuv) { - if (phys->enc_cdm_csc != conn_csc) { - hw_cdm = phys->hw_cdm; - rc = hw_cdm->ops.setup_csc_data(hw_cdm, - &sde_csc_10bit_convert[conn_csc]); - - if (rc) - SDE_ERROR_ENC(sde_enc, - "CSC setup failed rc %d\n", - rc); - SDE_DEBUG_ENC(sde_enc, - "updating CSC %d to %d\n", - phys->enc_cdm_csc, - conn_csc); - phys->enc_cdm_csc = conn_csc; - - } - } - } + SDE_ERROR_ENC(sde_enc, "kickoff conn%d failed rc %d\n", + sde_enc->cur_master->connector->base.id, + rc); } } @@ -1477,128 +1374,3 @@ enum sde_intf_mode sde_encoder_get_intf_mode(struct drm_encoder *encoder) return INTF_MODE_NONE; } - -/** - * sde_encoder_phys_setup_cdm - setup chroma down block - * @phys_enc: Pointer to physical encoder - * @output_type: HDMI/WB - * @format: Output format - * @roi: Output size - */ -void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc, - const struct sde_format *format, u32 output_type, - struct sde_rect *roi) -{ - struct drm_encoder *encoder = phys_enc->parent; - struct sde_encoder_virt *sde_enc = NULL; - struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm; - struct sde_hw_cdm_cfg *cdm_cfg = &phys_enc->cdm_cfg; - struct drm_connector *connector = phys_enc->connector; - int ret; - u32 csc_type = 0; - - if (!encoder) { - SDE_ERROR("invalid encoder\n"); - return; - } - sde_enc = to_sde_encoder_virt(encoder); - - if (!SDE_FORMAT_IS_YUV(format)) { - SDE_DEBUG_ENC(sde_enc, "[cdm_disable fmt:%x]\n", - format->base.pixel_format); - - if (hw_cdm && hw_cdm->ops.disable) - hw_cdm->ops.disable(hw_cdm); - - return; - } - - memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg)); - - cdm_cfg->output_width = roi->w; - cdm_cfg->output_height = roi->h; - cdm_cfg->output_fmt = format; - cdm_cfg->output_type = output_type; - cdm_cfg->output_bit_depth = SDE_FORMAT_IS_DX(format) ? - CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT; - - /* enable 10 bit logic */ - switch (cdm_cfg->output_fmt->chroma_sample) { - case SDE_CHROMA_RGB: - cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE; - cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; - break; - case SDE_CHROMA_H2V1: - cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE; - cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; - break; - case SDE_CHROMA_420: - cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE; - cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE; - break; - case SDE_CHROMA_H1V2: - default: - SDE_ERROR("unsupported chroma sampling type\n"); - cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE; - cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; - break; - } - - SDE_DEBUG_ENC(sde_enc, "[cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n", - cdm_cfg->output_width, - cdm_cfg->output_height, - cdm_cfg->output_fmt->base.pixel_format, - cdm_cfg->output_type, - cdm_cfg->output_bit_depth, - cdm_cfg->h_cdwn_type, - cdm_cfg->v_cdwn_type); - - /** - * Choose CSC matrix based on following rules: - * 1. If connector supports quantization select, - * pick Full-Range for better quality. - * 2. If non-CEA mode, then pick Full-Range as per CEA spec - * 3. Otherwise, pick Limited-Range as all other CEA modes - * need a limited range - */ - - if (output_type == CDM_CDWN_OUTPUT_HDMI) { - if (connector && connector->yuv_qs) - csc_type = SDE_CSC_RGB2YUV_601FR; - else if (connector && - sde_connector_mode_needs_full_range(connector)) - csc_type = SDE_CSC_RGB2YUV_601FR; - else - csc_type = SDE_CSC_RGB2YUV_601L; - } else if (output_type == CDM_CDWN_OUTPUT_WB) { - csc_type = SDE_CSC_RGB2YUV_601L; - } - - if (hw_cdm && hw_cdm->ops.setup_csc_data) { - ret = hw_cdm->ops.setup_csc_data(hw_cdm, - &sde_csc_10bit_convert[csc_type]); - if (ret < 0) { - SDE_ERROR("failed to setup CSC %d\n", ret); - return; - } - } - - /* Cache the CSC default matrix type */ - phys_enc->enc_cdm_csc = csc_type; - - if (hw_cdm && hw_cdm->ops.setup_cdwn) { - ret = hw_cdm->ops.setup_cdwn(hw_cdm, cdm_cfg); - if (ret < 0) { - SDE_ERROR("failed to setup CDM %d\n", ret); - return; - } - } - - if (hw_cdm && hw_cdm->ops.enable) { - ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg); - if (ret < 0) { - SDE_ERROR("failed to enable CDM %d\n", ret); - return; - } - } -} diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index aec844d640bd94bfc3601046d6af5dbb976c5058..2205dd98a927f1e21f224d7a57950b8c4ca4ad78 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -174,7 +174,6 @@ enum sde_intr_idx { * @split_role: Role to play in a split-panel configuration * @intf_mode: Interface mode * @intf_idx: Interface index on sde hardware - * @enc_cdm_csc: Cached CSC type of CDM block * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes * @enable_state: Enable state tracking * @vblank_refcount: Reference count of vblank request @@ -202,7 +201,6 @@ struct sde_encoder_phys { enum sde_enc_split_role split_role; enum sde_intf_mode intf_mode; enum sde_intf intf_idx; - enum sde_csc_type enc_cdm_csc; spinlock_t *enc_spinlock; enum sde_enc_enable_state enable_state; atomic_t vblank_refcount; @@ -351,8 +349,8 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( #endif void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc, - const struct sde_format *format, u32 output_type, - struct sde_rect *roi); + struct drm_framebuffer *fb, const struct sde_format *format, + struct sde_rect *wb_roi); /** * sde_encoder_helper_trigger_start - control start helper function diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c index 69a4237f7b67f920271a47ef0262dff817f69213..0b6ee302e231bfaca59d8c9918c897783456874c 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 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 @@ -242,20 +242,17 @@ static void sde_encoder_phys_vid_setup_timing_engine( SDE_DEBUG_VIDENC(vid_enc, "enabling mode:\n"); drm_mode_debug_printmodeline(&mode); - if (phys_enc->split_role != ENC_ROLE_SOLO || - (mode.private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420)) { + if (phys_enc->split_role != ENC_ROLE_SOLO) { mode.hdisplay >>= 1; mode.htotal >>= 1; mode.hsync_start >>= 1; mode.hsync_end >>= 1; - mode.hskew >>= 1; SDE_DEBUG_VIDENC(vid_enc, - "split_role %d, halve horizontal %d %d %d %d %d\n", + "split_role %d, halve horizontal %d %d %d %d\n", phys_enc->split_role, mode.hdisplay, mode.htotal, - mode.hsync_start, mode.hsync_end, - mode.hskew); + mode.hsync_start, mode.hsync_end); } drm_mode_to_intf_timing_params(vid_enc, &mode, &timing_params); @@ -410,9 +407,6 @@ static void sde_encoder_phys_vid_mode_set( return; } - phys_enc->hw_ctl = NULL; - phys_enc->hw_cdm = NULL; - rm = &phys_enc->sde_kms->rm; vid_enc = to_sde_encoder_phys_vid(phys_enc); phys_enc->cached_mode = *adj_mode; @@ -433,20 +427,6 @@ static void sde_encoder_phys_vid_mode_set( phys_enc->hw_ctl = NULL; return; } - - /* CDM is optional */ - sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CDM); - for (i = 0; i <= instance; i++) { - sde_rm_get_hw(rm, &iter); - if (i == instance) - phys_enc->hw_cdm = (struct sde_hw_cdm *) iter.hw; - } - - if (IS_ERR(phys_enc->hw_cdm)) { - SDE_ERROR("CDM required but not allocated: %ld\n", - PTR_ERR(phys_enc->hw_cdm)); - phys_enc->hw_cdm = NULL; - } } static int sde_encoder_phys_vid_control_vblank_irq( @@ -497,9 +477,6 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) struct sde_encoder_phys_vid *vid_enc; struct sde_hw_intf *intf; struct sde_hw_ctl *ctl; - struct sde_hw_cdm *hw_cdm = NULL; - struct drm_display_mode mode; - const struct sde_format *fmt = NULL; u32 flush_mask = 0; int ret; @@ -508,9 +485,7 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) SDE_ERROR("invalid encoder/device\n"); return; } - hw_cdm = phys_enc->hw_cdm; priv = phys_enc->parent->dev->dev_private; - mode = phys_enc->cached_mode; vid_enc = to_sde_encoder_phys_vid(phys_enc); intf = vid_enc->hw_intf; @@ -545,21 +520,7 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) goto end; } - if (mode.private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420) - fmt = sde_get_sde_format(DRM_FORMAT_YUV420); - - if (fmt) { - struct sde_rect hdmi_roi; - - hdmi_roi.w = mode.hdisplay; - hdmi_roi.h = mode.vdisplay; - sde_encoder_phys_setup_cdm(phys_enc, fmt, - CDM_CDWN_OUTPUT_HDMI, &hdmi_roi); - } - ctl->ops.get_bitmask_intf(ctl, &flush_mask, intf->idx); - if (ctl->ops.get_bitmask_cdm && hw_cdm) - ctl->ops.get_bitmask_cdm(ctl, &flush_mask, hw_cdm->idx); ctl->ops.update_pending_flush(ctl, flush_mask); SDE_DEBUG_VIDENC(vid_enc, "update pending flush ctl %d flush_mask %x\n", @@ -593,34 +554,21 @@ static void sde_encoder_phys_vid_get_hw_resources( struct drm_connector_state *conn_state) { struct sde_encoder_phys_vid *vid_enc; - struct sde_mdss_cfg *vid_catalog; if (!phys_enc || !hw_res) { SDE_ERROR("invalid arg(s), enc %d hw_res %d conn_state %d\n", - phys_enc != NULL, hw_res != NULL, conn_state != NULL); + phys_enc != 0, hw_res != 0, conn_state != 0); return; } - vid_catalog = phys_enc->sde_kms->catalog; vid_enc = to_sde_encoder_phys_vid(phys_enc); - if (!vid_enc->hw_intf || !vid_catalog) { - SDE_ERROR("invalid arg(s), hw_intf %d vid_catalog %d\n", - vid_enc->hw_intf != NULL, vid_catalog != NULL); + if (!vid_enc->hw_intf) { + SDE_ERROR("invalid arg(s), hw_intf\n"); return; } SDE_DEBUG_VIDENC(vid_enc, "\n"); - if (vid_enc->hw_intf->idx > INTF_MAX) { - SDE_ERROR("invalid arg(s), idx %d\n", - vid_enc->hw_intf->idx); - return; - } hw_res->intfs[vid_enc->hw_intf->idx - INTF_0] = INTF_MODE_VIDEO; - - if (vid_catalog->intf[vid_enc->hw_intf->idx - INTF_0].type - == INTF_HDMI) - hw_res->needs_cdm = true; - SDE_DEBUG_DRIVER("[vid] needs_cdm=%d\n", hw_res->needs_cdm); } static int sde_encoder_phys_vid_wait_for_vblank( @@ -765,11 +713,6 @@ static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc) SDE_ERROR_VIDENC(vid_enc, "invalid vblank refcount %d\n", atomic_read(&phys_enc->vblank_refcount)); - if (phys_enc->hw_cdm && phys_enc->hw_cdm->ops.disable) { - SDE_DEBUG_DRIVER("[cdm_disable]\n"); - phys_enc->hw_cdm->ops.disable(phys_enc->hw_cdm); - } - phys_enc->enable_state = SDE_ENC_DISABLED; } diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index 65b16419fcec4568dd667a778149cc3ec27d2254..a48962a2384b4de388fef6c98bd4da100e0d19f1 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -28,6 +28,24 @@ #define WBID(wb_enc) ((wb_enc) ? wb_enc->wb_dev->wb_idx : -1) +#define TO_S15D16(_x_) ((_x_) << 7) + +/** + * sde_rgb2yuv_601l - rgb to yuv color space conversion matrix + * + */ +static struct sde_csc_cfg sde_encoder_phys_wb_rgb2yuv_601l = { + { + TO_S15D16(0x0083), TO_S15D16(0x0102), TO_S15D16(0x0032), + TO_S15D16(0x1fb5), TO_S15D16(0x1f6c), TO_S15D16(0x00e1), + TO_S15D16(0x00e1), TO_S15D16(0x1f45), TO_S15D16(0x1fdc) + }, + { 0x00, 0x00, 0x00 }, + { 0x0040, 0x0200, 0x0200 }, + { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff }, + { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 }, +}; + /** * sde_encoder_phys_wb_is_master - report wb always as master encoder */ @@ -86,6 +104,96 @@ static void sde_encoder_phys_wb_set_traffic_shaper( wb_cfg->ts_cfg.en = false; } +/** + * sde_encoder_phys_setup_cdm - setup chroma down block + * @phys_enc: Pointer to physical encoder + * @fb: Pointer to output framebuffer + * @format: Output format + */ +void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc, + struct drm_framebuffer *fb, const struct sde_format *format, + struct sde_rect *wb_roi) +{ + struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm; + struct sde_hw_cdm_cfg *cdm_cfg = &phys_enc->cdm_cfg; + int ret; + + if (!SDE_FORMAT_IS_YUV(format)) { + SDE_DEBUG("[cdm_disable fmt:%x]\n", + format->base.pixel_format); + + if (hw_cdm && hw_cdm->ops.disable) + hw_cdm->ops.disable(hw_cdm); + + return; + } + + memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg)); + + cdm_cfg->output_width = wb_roi->w; + cdm_cfg->output_height = wb_roi->h; + cdm_cfg->output_fmt = format; + cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB; + cdm_cfg->output_bit_depth = SDE_FORMAT_IS_DX(format) ? + CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT; + + /* enable 10 bit logic */ + switch (cdm_cfg->output_fmt->chroma_sample) { + case SDE_CHROMA_RGB: + cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE; + cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; + break; + case SDE_CHROMA_H2V1: + cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE; + cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; + break; + case SDE_CHROMA_420: + cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE; + cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE; + break; + case SDE_CHROMA_H1V2: + default: + SDE_ERROR("unsupported chroma sampling type\n"); + cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE; + cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; + break; + } + + SDE_DEBUG("[cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n", + cdm_cfg->output_width, + cdm_cfg->output_height, + cdm_cfg->output_fmt->base.pixel_format, + cdm_cfg->output_type, + cdm_cfg->output_bit_depth, + cdm_cfg->h_cdwn_type, + cdm_cfg->v_cdwn_type); + + if (hw_cdm && hw_cdm->ops.setup_csc_data) { + ret = hw_cdm->ops.setup_csc_data(hw_cdm, + &sde_encoder_phys_wb_rgb2yuv_601l); + if (ret < 0) { + SDE_ERROR("failed to setup CSC %d\n", ret); + return; + } + } + + if (hw_cdm && hw_cdm->ops.setup_cdwn) { + ret = hw_cdm->ops.setup_cdwn(hw_cdm, cdm_cfg); + if (ret < 0) { + SDE_ERROR("failed to setup CDM %d\n", ret); + return; + } + } + + if (hw_cdm && hw_cdm->ops.enable) { + ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg); + if (ret < 0) { + SDE_ERROR("failed to enable CDM %d\n", ret); + return; + } + } +} + /** * sde_encoder_phys_wb_setup_fb - setup output framebuffer * @phys_enc: Pointer to physical encoder @@ -412,8 +520,7 @@ static void sde_encoder_phys_wb_setup( sde_encoder_phys_wb_set_traffic_shaper(phys_enc); - sde_encoder_phys_setup_cdm(phys_enc, wb_enc->wb_fmt, - CDM_CDWN_OUTPUT_WB, wb_roi); + sde_encoder_phys_setup_cdm(phys_enc, fb, wb_enc->wb_fmt, wb_roi); sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi); diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index a185eb338134bfabf4566ef22e29b25ea4afe5cd..eb398fbee8162775a255b519b9d3bbbd84e216af 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -689,7 +689,6 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg, { sblk->maxupscale = MAX_SSPP_UPSCALE; sblk->maxdwnscale = MAX_SSPP_DOWNSCALE; - sblk->format_list = plane_formats_yuv; sspp->id = SSPP_VIG0 + *vig_count; sspp->clk_ctrl = SDE_CLK_CTRL_VIG0 + *vig_count; sspp->type = SSPP_TYPE_VIG; @@ -760,7 +759,6 @@ static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg, { sblk->maxupscale = MAX_SSPP_UPSCALE; sblk->maxdwnscale = MAX_SSPP_DOWNSCALE; - sblk->format_list = plane_formats; sspp->id = SSPP_RGB0 + *rgb_count; sspp->clk_ctrl = SDE_CLK_CTRL_RGB0 + *rgb_count; sspp->type = SSPP_TYPE_RGB; @@ -801,7 +799,6 @@ static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg, set_bit(SDE_SSPP_CURSOR, &sspp->features); sblk->maxupscale = SSPP_UNITY_SCALE; sblk->maxdwnscale = SSPP_UNITY_SCALE; - sblk->format_list = cursor_formats; sspp->id = SSPP_CURSOR0 + *cursor_count; sspp->clk_ctrl = SDE_CLK_CTRL_CURSOR0 + *cursor_count; sspp->type = SSPP_TYPE_CURSOR; @@ -815,7 +812,6 @@ static void _sde_sspp_setup_dma(struct sde_mdss_cfg *sde_cfg, { sblk->maxupscale = SSPP_UNITY_SCALE; sblk->maxdwnscale = SSPP_UNITY_SCALE; - sblk->format_list = plane_formats; sspp->id = SSPP_DMA0 + *dma_count; sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + *dma_count; sspp->type = SSPP_TYPE_DMA; @@ -1295,7 +1291,6 @@ static int sde_wb_parse_dt(struct device_node *np, wb->xin_id = PROP_VALUE_ACCESS(prop_value, WB_XIN_ID, i); wb->vbif_idx = VBIF_NRT; wb->len = PROP_VALUE_ACCESS(prop_value, WB_LEN, 0); - wb->format_list = wb2_formats; if (!prop_exists[WB_LEN]) wb->len = DEFAULT_SDE_HW_BLOCK_LEN; sblk->maxlinewidth = sde_cfg->max_wb_linewidth; @@ -2080,11 +2075,6 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, goto end; } - if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_300) || - IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_301)) { - sde_cfg->has_hdr = true; - } - index = _sde_copy_formats(sde_cfg->dma_formats, dma_list_size, 0, plane_formats, ARRAY_SIZE(plane_formats)); index += _sde_copy_formats(sde_cfg->dma_formats, dma_list_size, diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h index 73bb77b7afa6f142e6418c895fd3d5dac69b243d..01204df48871e14b20b1301661cb1cc7c9843bff 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h @@ -655,7 +655,6 @@ struct sde_vp_cfg { * @csc_type csc or csc_10bit support. * @has_src_split source split feature status * @has_cdp Client driver prefetch feature status - * @has_hdr HDR feature support * @dma_formats Supported formats for dma pipe * @cursor_formats Supported formats for cursor pipe * @vig_formats Supported formats for vig pipe @@ -673,7 +672,7 @@ struct sde_mdss_cfg { u32 csc_type; bool has_src_split; bool has_cdp; - bool has_hdr; + u32 mdss_count; struct sde_mdss_base_cfg mdss[MAX_BLOCKS]; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c index 9ec81c227e602af16705a748121997c847742dcf..188649d946d601ac8baccdd0d98e4a203fcb5784 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c @@ -227,7 +227,7 @@ int sde_hw_cdm_enable(struct sde_hw_cdm *ctx, return -EINVAL; if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { - if (fmt->chroma_sample == SDE_CHROMA_H1V2) + if (fmt->chroma_sample != SDE_CHROMA_H1V2) return -EINVAL; /*unsupported format */ opmode = BIT(0); opmode |= (fmt->chroma_sample << 1); diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h index 92dd829eee3e5611b79bd1b17542cc8e9172b627..2592fe26cb38521cda0ca1903d68adc6b518a7c1 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h @@ -63,8 +63,6 @@ enum sde_format_flags { (((X)->fetch_mode == SDE_FETCH_UBWC) && \ test_bit(SDE_FORMAT_FLAG_COMPRESSED_BIT, (X)->flag)) -#define TO_S15D16(_x_) ((_x_) << 7) - #define SDE_BLEND_FG_ALPHA_FG_CONST (0 << 0) #define SDE_BLEND_FG_ALPHA_BG_CONST (1 << 0) #define SDE_BLEND_FG_ALPHA_FG_PIXEL (2 << 0) @@ -341,15 +339,6 @@ enum sde_3d_blend_mode { BLEND_3D_MAX }; -enum sde_csc_type { - SDE_CSC_RGB2YUV_601L, - SDE_CSC_RGB2YUV_601FR, - SDE_CSC_RGB2YUV_709L, - SDE_CSC_RGB2YUV_2020L, - SDE_CSC_RGB2YUV_2020FR, - SDE_MAX_CSC -}; - /** struct sde_format - defines the format configuration which * allows SDE HW to correctly fetch and decode the format * @base: base msm_format struture containing fourcc code diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index cdf67c0aa8644a0619e806debbecda4c9f5cac2c..031493aa42b8915006e76b40d777c5f2ca2565d0 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -328,12 +328,24 @@ static int sde_debugfs_danger_init(struct sde_kms *sde_kms, static int sde_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { + struct sde_kms *sde_kms = to_sde_kms(kms); + struct drm_device *dev = sde_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + + sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); + return sde_crtc_vblank(crtc, true); } static void sde_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { + struct sde_kms *sde_kms = to_sde_kms(kms); + struct drm_device *dev = sde_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + sde_crtc_vblank(crtc, false); + + sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); } static void sde_kms_prepare_commit(struct msm_kms *kms, @@ -343,9 +355,6 @@ static void sde_kms_prepare_commit(struct msm_kms *kms, struct drm_device *dev = sde_kms->dev; struct msm_drm_private *priv = dev->dev_private; - if (sde_kms->splash_info.handoff) - sde_splash_clean_up_exit_lk(kms); - sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); } @@ -594,8 +603,6 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .set_property = sde_hdmi_set_property, .get_property = sde_hdmi_get_property, .pre_kickoff = sde_hdmi_pre_kickoff, - .mode_needs_full_range = sde_hdmi_mode_needs_full_range, - .get_csc_type = sde_hdmi_get_csc_type }; struct msm_display_info info = {0}; struct drm_encoder *encoder; @@ -990,15 +997,8 @@ static void _sde_kms_hw_destroy(struct sde_kms *sde_kms, sde_hw_catalog_deinit(sde_kms->catalog); sde_kms->catalog = NULL; - if (sde_kms->splash_info.handoff) { - if (sde_kms->core_client) - sde_splash_destroy(&sde_kms->splash_info, - &priv->phandle, sde_kms->core_client); - } - if (sde_kms->core_client) - sde_power_client_destroy(&priv->phandle, - sde_kms->core_client); + sde_power_client_destroy(&priv->phandle, sde_kms->core_client); sde_kms->core_client = NULL; if (sde_kms->vbif[VBIF_NRT]) @@ -1110,24 +1110,6 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) continue; } - /* Attaching smmu means IOMMU HW starts to work immediately. - * However, display HW in LK is still accessing memory - * while the memory map is not done yet. - * So first set DOMAIN_ATTR_EARLY_MAP attribute 1 to bypass - * stage 1 translation in IOMMU HW. - */ - if ((i == MSM_SMMU_DOMAIN_UNSECURE) && - sde_kms->splash_info.handoff) { - ret = mmu->funcs->set_property(mmu, - DOMAIN_ATTR_EARLY_MAP, - &sde_kms->splash_info.handoff); - if (ret) { - SDE_ERROR("failed to set map att: %d\n", ret); - mmu->funcs->destroy(mmu); - goto fail; - } - } - aspace = msm_gem_smmu_address_space_create(sde_kms->dev->dev, mmu, "sde"); if (IS_ERR(aspace)) { @@ -1145,19 +1127,6 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) goto fail; } - /* - * It's safe now to map the physical memory blcok LK accesses. - */ - if ((i == MSM_SMMU_DOMAIN_UNSECURE) && - sde_kms->splash_info.handoff) { - ret = sde_splash_smmu_map(sde_kms->dev, mmu, - &sde_kms->splash_info); - if (ret) { - SDE_ERROR("map rsv mem failed: %d\n", ret); - msm_gem_address_space_put(aspace); - goto fail; - } - } } return 0; @@ -1172,7 +1141,6 @@ static int sde_kms_hw_init(struct msm_kms *kms) struct sde_kms *sde_kms; struct drm_device *dev; struct msm_drm_private *priv; - struct sde_splash_info *sinfo; int i, rc = -EINVAL; if (!kms) { @@ -1262,35 +1230,6 @@ static int sde_kms_hw_init(struct msm_kms *kms) goto power_error; } - /* - * Read the DISP_INTF_SEL register to check - * whether early display is enabled in LK. - */ - rc = sde_splash_get_handoff_status(kms); - if (rc) { - SDE_ERROR("get early splash status failed: %d\n", rc); - goto power_error; - } - - /* - * when LK has enabled early display, sde_splash_parse_dt and - * sde_splash_init must be called. The first function is to parse the - * mandatory memory node for splash function, and the second function - * will first do bandwidth voting job, because display hardware is now - * accessing AHB data bus, otherwise device reboot will happen, and then - * to check if the memory is reserved. - */ - sinfo = &sde_kms->splash_info; - if (sinfo->handoff) { - rc = sde_splash_parse_dt(dev); - if (rc) { - SDE_ERROR("parse dt for splash info failed: %d\n", rc); - goto power_error; - } - - sde_splash_init(&priv->phandle, kms); - } - for (i = 0; i < sde_kms->catalog->vbif_count; i++) { u32 vbif_idx = sde_kms->catalog->vbif[i].id; @@ -1365,10 +1304,7 @@ static int sde_kms_hw_init(struct msm_kms *kms) */ dev->mode_config.allow_fb_modifiers = true; - if (!sde_kms->splash_info.handoff) - sde_power_resource_enable(&priv->phandle, - sde_kms->core_client, false); - + sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); return 0; drm_obj_init_err: diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index fa0288b89b91c4ca15c4d258d947f4c330a5b349..44f6be959ac97755711a17064efd2171603e4417 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -34,7 +34,6 @@ #include "sde_power_handle.h" #include "sde_irq.h" #include "sde_core_perf.h" -#include "sde_splash.h" #define DRMID(x) ((x) ? (x)->base.id : -1) @@ -158,9 +157,6 @@ struct sde_kms { bool has_danger_ctrl; void **hdmi_displays; int hdmi_display_count; - - /* splash handoff structure */ - struct sde_splash_info splash_info; }; struct vsync_info { @@ -281,12 +277,10 @@ struct sde_kms_info { /** * SDE_KMS_INFO_DATALEN - Macro for accessing sde_kms_info data length - * it adds an extra character length to count null. * @S: Pointer to sde_kms_info structure * Returns: Size of available byte data */ -#define SDE_KMS_INFO_DATALEN(S) ((S) ? ((struct sde_kms_info *)(S))->len + 1 \ - : 0) +#define SDE_KMS_INFO_DATALEN(S) ((S) ? ((struct sde_kms_info *)(S))->len : 0) /** * sde_kms_info_reset - reset sde_kms_info structure diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index 6e2ccfa8e428bf6994ade2e6fadcd134e0ec9563..6fe1d1629d224f1ea4fc48efdf9a07b8932382bf 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -34,14 +34,6 @@ #include "sde_plane.h" #include "sde_color_processing.h" -static bool suspend_blank = true; -module_param(suspend_blank, bool, 0400); -MODULE_PARM_DESC(suspend_blank, - "If set, active planes will force their outputs to black,\n" - "by temporarily enabling the color fill, when recovering\n" - "from a system resume instead of attempting to display the\n" - "last provided frame buffer."); - #define SDE_DEBUG_PLANE(pl, fmt, ...) SDE_DEBUG("plane%d " fmt,\ (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__) @@ -146,7 +138,6 @@ struct sde_plane { struct sde_debugfs_regset32 debugfs_src; struct sde_debugfs_regset32 debugfs_scaler; struct sde_debugfs_regset32 debugfs_csc; - bool debugfs_default_scale; }; #define to_sde_plane(x) container_of(x, struct sde_plane, base) @@ -695,20 +686,9 @@ static int _sde_plane_setup_scaler3_lut(struct sde_phy_plane *pp, struct sde_plane_state *pstate) { struct sde_plane *psde = pp->sde_plane; - struct sde_hw_scaler3_cfg *cfg; + struct sde_hw_scaler3_cfg *cfg = pp->scaler3_cfg; int ret = 0; - if (!pp || !pp->scaler3_cfg) { - SDE_ERROR("invalid args\n"); - return -EINVAL; - } else if (!pstate) { - /* pstate is expected to be null on forced color fill */ - SDE_DEBUG("null pstate\n"); - return -EINVAL; - } - - cfg = pp->scaler3_cfg; - cfg->dir_lut = msm_property_get_blob( &psde->property_info, pstate->property_blobs, &cfg->dir_len, @@ -743,7 +723,6 @@ static void _sde_plane_setup_scaler3(struct sde_phy_plane *pp, } memset(scale_cfg, 0, sizeof(*scale_cfg)); - memset(&pp->pixel_ext, 0, sizeof(struct sde_hw_pixel_ext)); decimated = DECIMATED_DIMENSION(src_w, pp->pipe_cfg.horz_decimation); @@ -1091,8 +1070,7 @@ static void _sde_plane_setup_scaler(struct sde_phy_plane *pp, int error; error = _sde_plane_setup_scaler3_lut(pp, pstate); - if (error || !pp->pixel_ext_usr || - psde->debugfs_default_scale) { + if (error || !pp->pixel_ext_usr) { memset(pe, 0, sizeof(struct sde_hw_pixel_ext)); /* calculate default config for QSEED3 */ _sde_plane_setup_scaler3(pp, @@ -1103,8 +1081,7 @@ static void _sde_plane_setup_scaler(struct sde_phy_plane *pp, pp->scaler3_cfg, fmt, chroma_subsmpl_h, chroma_subsmpl_v); } - } else if (!pp->pixel_ext_usr || !pstate || - psde->debugfs_default_scale) { + } else if (!pp->pixel_ext_usr) { uint32_t deci_dim, i; /* calculate default configuration for QSEED2 */ @@ -1724,8 +1701,8 @@ void sde_plane_flush(struct drm_plane *plane) */ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) { if (psde->is_error) - /* force white frame with 100% alpha pipe output on error */ - _sde_plane_color_fill(pp, 0xFFFFFF, 0xFF); + /* force white frame with 0% alpha pipe output on error */ + _sde_plane_color_fill(pp, 0xFFFFFF, 0x0); else if (pp->color_fill & SDE_PLANE_COLOR_FILL_FLAG) /* force 100% alpha */ _sde_plane_color_fill(pp, pp->color_fill, 0xFF); @@ -1734,10 +1711,6 @@ void sde_plane_flush(struct drm_plane *plane) pp->pipe_hw->ops.setup_csc(pp->pipe_hw, pp->csc_ptr); } - /* force black color fill during suspend */ - if (msm_is_suspend_state(plane->dev) && suspend_blank) - _sde_plane_color_fill(pp, 0x0, 0x0); - /* flag h/w flush complete */ if (plane->state) to_sde_plane_state(plane->state)->pending = false; @@ -2609,10 +2582,6 @@ static void _sde_plane_init_debugfs(struct sde_plane *psde, sde_debugfs_create_regset32("scaler_blk", S_IRUGO, psde->debugfs_root, &psde->debugfs_scaler); - debugfs_create_bool("default_scaling", - 0644, - psde->debugfs_root, - &psde->debugfs_default_scale); sde_debugfs_setup_regset32(&psde->debugfs_csc, sblk->csc_blk.base + cfg->base, diff --git a/drivers/gpu/drm/msm/sde_edid_parser.c b/drivers/gpu/drm/msm/sde_edid_parser.c index 68246253bb70388fb798d502aa77d51a6c589305..ca9229ede251022e76e6697492c16b7e250d1a23 100644 --- a/drivers/gpu/drm/msm/sde_edid_parser.c +++ b/drivers/gpu/drm/msm/sde_edid_parser.c @@ -229,17 +229,10 @@ u32 video_format) { u8 cea_mode = 0; struct drm_display_mode *mode; - u32 mode_fmt_flags = 0; /* Need to add Y420 support flag to the modes */ list_for_each_entry(mode, &connector->probed_modes, head) { - /* Cache the format flags before clearing */ - mode_fmt_flags = mode->flags; - /* Clear the RGB/YUV format flags before calling upstream API */ - mode->flags &= ~SDE_DRM_MODE_FLAG_FMT_MASK; cea_mode = drm_match_cea_mode(mode); - /* Restore the format flags */ - mode->flags = mode_fmt_flags; if ((cea_mode != 0) && (cea_mode == video_format)) { SDE_EDID_DEBUG("%s found match for %d ", __func__, video_format); @@ -253,7 +246,7 @@ struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl, const u8 *db) { u32 offset = 0; - u8 cmdb_len = 0; + u8 len = 0; u8 svd_len = 0; const u8 *svd = NULL; u32 i = 0, j = 0; @@ -269,8 +262,10 @@ const u8 *db) return; } SDE_EDID_DEBUG("%s +\n", __func__); - cmdb_len = db[0] & 0x1f; + len = db[0] & 0x1f; + if (len < 7) + return; /* Byte 3 to L+1 contain SVDs */ offset += 2; @@ -278,24 +273,20 @@ const u8 *db) if (svd) { /*moving to the next byte as vic info begins there*/ - svd_len = svd[0] & 0x1f; ++svd; + svd_len = svd[0] & 0x1f; } for (i = 0; i < svd_len; i++, j++) { - video_format = *(svd + i) & 0x7F; - if (cmdb_len == 1) { - /* If cmdb_len is 1, it means all SVDs support YUV */ - sde_edid_set_y420_support(connector, video_format); - } else if (db[offset] & (1 << j)) { + video_format = *svd & 0x7F; + if (db[offset] & (1 << j)) sde_edid_set_y420_support(connector, video_format); - if (j & 0x80) { - j = j/8; - offset++; - if (offset >= cmdb_len) - break; - } + if (j & 0x80) { + j = j/8; + offset++; + if (offset >= len) + break; } } diff --git a/drivers/gpu/drm/msm/sde_edid_parser.h b/drivers/gpu/drm/msm/sde_edid_parser.h index 59e3dceca33c30180276942b3bf9426439d7ead5..1143dc2c7bec8f5969c372c6559f5ce769aacf2f 100644 --- a/drivers/gpu/drm/msm/sde_edid_parser.h +++ b/drivers/gpu/drm/msm/sde_edid_parser.h @@ -33,8 +33,6 @@ #define SDE_CEA_EXT 0x02 #define SDE_EXTENDED_TAG 0x07 -#define SDE_DRM_MODE_FLAG_FMT_MASK (0x3 << 20) - enum extended_data_block_types { VIDEO_CAPABILITY_DATA_BLOCK = 0x0, VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01, diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index fcecaf5b5526766ad6243188778a96f5b20013f8..a9b01bcf7d0a2242cf181ef31a77cf9150e6e8f8 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -3394,13 +3394,6 @@ void radeon_combios_asic_init(struct drm_device *dev) rdev->pdev->subsystem_vendor == 0x103c && rdev->pdev->subsystem_device == 0x280a) return; - /* quirk for rs4xx Toshiba Sattellite L20-183 latop to make it resume - * - it hangs on resume inside the dynclk 1 table. - */ - if (rdev->family == CHIP_RS400 && - rdev->pdev->subsystem_vendor == 0x1179 && - rdev->pdev->subsystem_device == 0xff31) - return; /* DYN CLK 1 */ table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index a77521695c9a4becadd8e3a5f89ba184ac881f60..4aa2cbe4c85fae3212aae4012bf957e16d2d6f83 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -127,10 +127,6 @@ static struct radeon_px_quirk radeon_px_quirk_list[] = { * https://bugzilla.kernel.org/show_bug.cgi?id=51381 */ { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX }, - /* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU - * https://bugs.freedesktop.org/show_bug.cgi?id=101491 - */ - { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX }, /* macbook pro 8.2 */ { PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP }, { 0, 0, 0, 0, 0 }, diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 1244cdf528599312d9596290b37077958fafa09a..f300eba95bb1bff32ad8e9be2a8250779ec255b6 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -81,10 +81,8 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, return -ENOMEM; size = roundup(size, PAGE_SIZE); ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size); - if (ret != 0) { - kfree(bo); + if (ret != 0) return ret; - } bo->dumb = false; virtio_gpu_init_ttm_placement(bo, pinned); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c index 1f013d45c9e9a3959dfa19300ba76fc37820592a..13db8a2851edd475cc1e44adedd44796c3ccbca1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c @@ -321,7 +321,6 @@ void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man) list_for_each_entry_safe(entry, next, &man->list, head) vmw_cmdbuf_res_free(man, entry); - drm_ht_remove(&man->resources); kfree(man); } diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 7cab049771de30c4fa97acac88bc4fc4aa149a05..6521ec01413e44d6e06560a13043a749eca6abb0 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -902,9 +902,6 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev, device->pwrctrl.bus_control = of_property_read_bool(node, "qcom,bus-control"); - device->pwrctrl.input_disable = of_property_read_bool(node, - "qcom,disable-wake-on-touch"); - return 0; } @@ -1019,19 +1016,15 @@ static int adreno_probe(struct platform_device *pdev) /* Initialize coresight for the target */ adreno_coresight_init(adreno_dev); + adreno_input_handler.private = device; + #ifdef CONFIG_INPUT - if (!device->pwrctrl.input_disable) { - adreno_input_handler.private = device; - /* - * It isn't fatal if we cannot register the input handler. Sad, - * perhaps, but not fatal - */ - if (input_register_handler(&adreno_input_handler)) { - adreno_input_handler.private = NULL; - KGSL_DRV_ERR(device, - "Unable to register the input handler\n"); - } - } + /* + * It isn't fatal if we cannot register the input handler. Sad, + * perhaps, but not fatal + */ + if (input_register_handler(&adreno_input_handler)) + KGSL_DRV_ERR(device, "Unable to register the input handler\n"); #endif out: if (status) { @@ -1083,8 +1076,7 @@ static int adreno_remove(struct platform_device *pdev) _adreno_free_memories(adreno_dev); #ifdef CONFIG_INPUT - if (adreno_input_handler.private) - input_unregister_handler(&adreno_input_handler); + input_unregister_handler(&adreno_input_handler); #endif adreno_sysfs_close(adreno_dev); @@ -1317,10 +1309,6 @@ static int _adreno_start(struct adreno_device *adreno_dev) /* make sure ADRENO_DEVICE_STARTED is not set here */ BUG_ON(test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)); - /* disallow l2pc during wake up to improve GPU wake up time */ - kgsl_pwrctrl_update_l2pc(&adreno_dev->dev, - KGSL_L2PC_WAKEUP_TIMEOUT); - pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, pmqos_wakeup_vote); diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 4a0acdcf8844d7cdf3e6a06c275e346f74582763..218d08e6dfc3273273a407cdea4a70bb3a42d828 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -568,8 +568,6 @@ enum adreno_regs { ADRENO_REG_RBBM_RBBM_CTL, ADRENO_REG_UCHE_INVALIDATE0, ADRENO_REG_UCHE_INVALIDATE1, - ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO, - ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO, ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI, ADRENO_REG_RBBM_SECVID_TRUST_CONTROL, @@ -1510,60 +1508,21 @@ static inline void adreno_ringbuffer_set_pagetable(struct adreno_ringbuffer *rb, spin_unlock_irqrestore(&rb->preempt_lock, flags); } -static inline bool is_power_counter_overflow(struct adreno_device *adreno_dev, - unsigned int reg, unsigned int prev_val, unsigned int *perfctr_pwr_hi) -{ - unsigned int val; - bool ret = false; - - /* - * If prev_val is zero, it is first read after perf counter reset. - * So set perfctr_pwr_hi register to zero. - */ - if (prev_val == 0) { - *perfctr_pwr_hi = 0; - return ret; - } - adreno_readreg(adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, &val); - if (val != *perfctr_pwr_hi) { - *perfctr_pwr_hi = val; - ret = true; - } - return ret; -} - static inline unsigned int counter_delta(struct kgsl_device *device, unsigned int reg, unsigned int *counter) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned int val; unsigned int ret = 0; - bool overflow = true; - static unsigned int perfctr_pwr_hi; /* Read the value */ kgsl_regread(device, reg, &val); - if (adreno_is_a5xx(adreno_dev) && reg == adreno_getreg - (adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO)) - overflow = is_power_counter_overflow(adreno_dev, reg, - *counter, &perfctr_pwr_hi); - /* Return 0 for the first read */ if (*counter != 0) { - if (val >= *counter) { - ret = val - *counter; - } else if (overflow == true) { + if (val < *counter) ret = (0xFFFFFFFF - *counter) + val; - } else { - /* - * Since KGSL got abnormal value from the counter, - * We will drop the value from being accumulated. - */ - pr_warn_once("KGSL: Abnormal value :0x%x (0x%x) from perf counter : 0x%x\n", - val, *counter, reg); - return 0; - } + else + ret = val - *counter; } *counter = val; diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 0e3e5b64bdc720298b31f47b1ec0c906d5717e35..423071811b43b5fac63b6c2b0440867464bda3dc 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -1530,10 +1530,6 @@ static unsigned int a3xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { A3XX_UCHE_CACHE_INVALIDATE0_REG), ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE1, A3XX_UCHE_CACHE_INVALIDATE1_REG), - ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO, - A3XX_RBBM_PERFCTR_RBBM_0_LO), - ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, - A3XX_RBBM_PERFCTR_RBBM_0_HI), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO, A3XX_RBBM_PERFCTR_LOAD_VALUE_LO), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI, diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c index 6170cc263e4abe7b8aefc885b233812791b48bdd..5ca04e522270661a1c1c182a54876f090344a911 100644 --- a/drivers/gpu/msm/adreno_a4xx.c +++ b/drivers/gpu/msm/adreno_a4xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -806,10 +806,6 @@ static unsigned int a4xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SW_RESET_CMD, A4XX_RBBM_SW_RESET_CMD), ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0, A4XX_UCHE_INVALIDATE0), ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE1, A4XX_UCHE_INVALIDATE1), - ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO, - A4XX_RBBM_PERFCTR_RBBM_0_LO), - ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, - A4XX_RBBM_PERFCTR_RBBM_0_HI), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO, A4XX_RBBM_PERFCTR_LOAD_VALUE_LO), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI, diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 3fb13c7a0814fdad34ea2943c873400154ea6374..0715022be6e390ae50690263f8a9344ff25e3397 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -715,10 +715,6 @@ static int _load_gpmu_firmware(struct adreno_device *adreno_dev) if (ret) goto err; - /* Integer overflow check for cmd_size */ - if (data[2] > (data[0] - 2)) - goto err; - cmds = data + data[2] + 3; cmd_size = data[0] - data[2] - 2; @@ -2073,9 +2069,6 @@ static void a5xx_start(struct adreno_device *adreno_dev) } - /* Disable All flat shading optimization */ - kgsl_regrmw(device, A5XX_VPC_DBG_ECO_CNTL, 0, 0x1 << 10); - /* * VPC corner case with local memory load kill leads to corrupt * internal state. Normal Disable does not work for all a5x chips. @@ -3076,10 +3069,6 @@ static unsigned int a5xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { ADRENO_REG_DEFINE(ADRENO_REG_RBBM_BLOCK_SW_RESET_CMD2, A5XX_RBBM_BLOCK_SW_RESET_CMD2), ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0, A5XX_UCHE_INVALIDATE0), - ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO, - A5XX_RBBM_PERFCTR_RBBM_0_LO), - ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, - A5XX_RBBM_PERFCTR_RBBM_0_HI), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO, A5XX_RBBM_PERFCTR_LOAD_VALUE_LO), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI, diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c index 883a9810fbf415a73889f099aef802798a1643ab..0e56731b16e2025d37cfb2054f2fc85283de566f 100644 --- a/drivers/gpu/msm/adreno_a5xx_preempt.c +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -537,42 +537,13 @@ static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED, "smmu_info"); } - -static void a5xx_preemption_iommu_close(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); - - kgsl_free_global(device, &iommu->smmu_info); -} - #else static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) { return -ENODEV; } - -static void a5xx_preemption_iommu_close(struct adreno_device *adreno_dev) -{ -} #endif -static void a5xx_preemption_close(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_preemption *preempt = &adreno_dev->preempt; - struct adreno_ringbuffer *rb; - unsigned int i; - - del_timer(&preempt->timer); - kgsl_free_global(device, &preempt->counters); - a5xx_preemption_iommu_close(adreno_dev); - - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - kgsl_free_global(device, &rb->preemption_desc); - } -} - int a5xx_preemption_init(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -597,7 +568,7 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev) A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0, "preemption_counters"); if (ret) - goto err; + return ret; addr = preempt->counters.gpuaddr; @@ -605,16 +576,10 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev) FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { ret = a5xx_preemption_ringbuffer_init(adreno_dev, rb, addr); if (ret) - goto err; + return ret; addr += A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE; } - ret = a5xx_preemption_iommu_init(adreno_dev); - -err: - if (ret) - a5xx_preemption_close(device); - - return ret; + return a5xx_preemption_iommu_init(adreno_dev); } diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 2027ac66f73720d1bec5699a664e32823eb743bd..5306303b8d15856921a072e2aa67e7ea8262884c 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -131,8 +131,6 @@ typedef void (*reg_read_fill_t)(struct kgsl_device *device, int i, static void sync_event_print(struct seq_file *s, struct kgsl_drawobj_sync_event *sync_event) { - unsigned long flags; - switch (sync_event->type) { case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP: { seq_printf(s, "sync: ctx: %d ts: %d", @@ -140,13 +138,9 @@ static void sync_event_print(struct seq_file *s, break; } case KGSL_CMD_SYNCPOINT_TYPE_FENCE: - spin_lock_irqsave(&sync_event->handle_lock, flags); - seq_printf(s, "sync: [%pK] %s", sync_event->handle, (sync_event->handle && sync_event->handle->fence) ? sync_event->handle->fence->name : "NULL"); - - spin_unlock_irqrestore(&sync_event->handle_lock, flags); break; default: seq_printf(s, "sync: type: %d", sync_event->type); diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 1a94e71f5c1d33d36d7c710a2ec72c2e8ccdc16f..8902c3175c791d1a6378ea017674cdfeef543be9 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -1460,9 +1460,7 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, spin_unlock(&drawctxt->lock); - if (device->pwrctrl.l2pc_update_queue) - kgsl_pwrctrl_update_l2pc(&adreno_dev->dev, - KGSL_L2PC_QUEUE_TIMEOUT); + kgsl_pwrctrl_update_l2pc(&adreno_dev->dev); /* Add the context to the dispatcher pending list */ dispatcher_queue_context(adreno_dev, drawctxt); diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index ddc53edce3c1221e60020d577839270877f1210d..d79d9613043f3d1aca719209071f3dd5bb43ea74 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -26,7 +26,6 @@ #include "adreno_iommu.h" #include "adreno_pm4types.h" #include "adreno_ringbuffer.h" -#include "adreno_trace.h" #include "a3xx_reg.h" #include "adreno_a5xx.h" @@ -59,7 +58,6 @@ static void _cff_write_ringbuffer(struct adreno_ringbuffer *rb) } static void adreno_get_submit_time(struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb, struct adreno_submit_time *time) { unsigned long flags; @@ -89,9 +87,6 @@ static void adreno_get_submit_time(struct adreno_device *adreno_dev, } else time->ticks = 0; - /* Trace the GPU time to create a mapping to ftrace time */ - trace_adreno_cmdbatch_sync(rb->drawctxt_active, time->ticks); - /* Get the kernel clock for time since boot */ time->ktime = local_clock(); @@ -133,7 +128,7 @@ void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb, _cff_write_ringbuffer(rb); if (time != NULL) - adreno_get_submit_time(adreno_dev, rb, time); + adreno_get_submit_time(adreno_dev, time); adreno_ringbuffer_wptr(adreno_dev, rb); } diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h index 74c4c4e6e1fac942b102663e497cce1bb9d86bf9..16ca0980cfbeea2691a5ec7a6c023f7940f0d6d4 100644 --- a/drivers/gpu/msm/adreno_trace.h +++ b/drivers/gpu/msm/adreno_trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -148,29 +148,6 @@ TRACE_EVENT(adreno_cmdbatch_retired, ) ); -TRACE_EVENT(adreno_cmdbatch_sync, - TP_PROTO(struct adreno_context *drawctxt, - uint64_t ticks), - TP_ARGS(drawctxt, ticks), - TP_STRUCT__entry( - __field(unsigned int, id) - __field(unsigned int, timestamp) - __field(uint64_t, ticks) - __field(int, prio) - ), - TP_fast_assign( - __entry->id = drawctxt->base.id; - __entry->timestamp = drawctxt->timestamp; - __entry->ticks = ticks; - __entry->prio = drawctxt->base.priority; - ), - TP_printk( - "ctx=%u ctx_prio=%d ts=%u ticks=%lld", - __entry->id, __entry->prio, __entry->timestamp, - __entry->ticks - ) -); - TRACE_EVENT(adreno_cmdbatch_fault, TP_PROTO(struct kgsl_drawobj_cmd *cmdobj, unsigned int fault), TP_ARGS(cmdobj, fault), diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 5a74c8e2bb93e377dd6154087eb74e6e8cf294d8..990c9bca51272733c011ae902c994eafec05b226 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2210,23 +2210,21 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device, if (fd != 0) dmabuf = dma_buf_get(fd - 1); } + up_read(¤t->mm->mmap_sem); - if (IS_ERR_OR_NULL(dmabuf)) { - up_read(¤t->mm->mmap_sem); + if (IS_ERR_OR_NULL(dmabuf)) return dmabuf ? PTR_ERR(dmabuf) : -ENODEV; - } ret = kgsl_setup_dma_buf(device, pagetable, entry, dmabuf); if (ret) { dma_buf_put(dmabuf); - up_read(¤t->mm->mmap_sem); return ret; } /* Setup the user addr/cache mode for cache operations */ entry->memdesc.useraddr = hostptr; _setup_cache_mode(entry, vma); - up_read(¤t->mm->mmap_sem); + return 0; } #else @@ -2263,7 +2261,7 @@ static long _gpuobj_map_useraddr(struct kgsl_device *device, struct kgsl_mem_entry *entry, struct kgsl_gpuobj_import *param) { - struct kgsl_gpuobj_import_useraddr useraddr = {0}; + struct kgsl_gpuobj_import_useraddr useraddr; int ret; param->flags &= KGSL_MEMFLAGS_GPUREADONLY @@ -3451,7 +3449,7 @@ static int _sparse_add_to_bind_tree(struct kgsl_mem_entry *entry, struct sparse_bind_object *new; struct rb_node **node, *parent = NULL; - new = kzalloc(sizeof(*new), GFP_ATOMIC); + new = kzalloc(sizeof(*new), GFP_KERNEL); if (new == NULL) return -ENOMEM; @@ -3485,6 +3483,7 @@ static int _sparse_rm_from_bind_tree(struct kgsl_mem_entry *entry, struct sparse_bind_object *obj, uint64_t v_offset, uint64_t size) { + spin_lock(&entry->bind_lock); if (v_offset == obj->v_off && size >= obj->size) { /* * We are all encompassing, remove the entry and free @@ -3517,6 +3516,7 @@ static int _sparse_rm_from_bind_tree(struct kgsl_mem_entry *entry, obj->size = v_offset - obj->v_off; + spin_unlock(&entry->bind_lock); ret = _sparse_add_to_bind_tree(entry, v_offset + size, obj->p_memdesc, obj->p_off + (v_offset - obj->v_off) + size, @@ -3526,10 +3526,11 @@ static int _sparse_rm_from_bind_tree(struct kgsl_mem_entry *entry, return ret; } + spin_unlock(&entry->bind_lock); + return 0; } -/* entry->bind_lock must be held by the caller */ static struct sparse_bind_object *_find_containing_bind_obj( struct kgsl_mem_entry *entry, uint64_t offset, uint64_t size) @@ -3537,6 +3538,8 @@ static struct sparse_bind_object *_find_containing_bind_obj( struct sparse_bind_object *obj = NULL; struct rb_node *node = entry->bind_tree.rb_node; + spin_lock(&entry->bind_lock); + while (node != NULL) { obj = rb_entry(node, struct sparse_bind_object, node); @@ -3555,16 +3558,33 @@ static struct sparse_bind_object *_find_containing_bind_obj( } } + spin_unlock(&entry->bind_lock); + return obj; } -/* entry->bind_lock must be held by the caller */ static int _sparse_unbind(struct kgsl_mem_entry *entry, struct sparse_bind_object *bind_obj, uint64_t offset, uint64_t size) { + struct kgsl_memdesc *memdesc = bind_obj->p_memdesc; + struct kgsl_pagetable *pt = memdesc->pagetable; int ret; + if (memdesc->cur_bindings < (size / PAGE_SIZE)) + return -EINVAL; + + memdesc->cur_bindings -= size / PAGE_SIZE; + + ret = kgsl_mmu_unmap_offset(pt, memdesc, + entry->memdesc.gpuaddr, offset, size); + if (ret) + return ret; + + ret = kgsl_mmu_sparse_dummy_map(pt, &entry->memdesc, offset, size); + if (ret) + return ret; + ret = _sparse_rm_from_bind_tree(entry, bind_obj, offset, size); if (ret == 0) { atomic_long_sub(size, &kgsl_driver.stats.mapped); @@ -3578,8 +3598,6 @@ static long sparse_unbind_range(struct kgsl_sparse_binding_object *obj, struct kgsl_mem_entry *virt_entry) { struct sparse_bind_object *bind_obj; - struct kgsl_memdesc *memdesc; - struct kgsl_pagetable *pt; int ret = 0; uint64_t size = obj->size; uint64_t tmp_size = obj->size; @@ -3587,14 +3605,9 @@ static long sparse_unbind_range(struct kgsl_sparse_binding_object *obj, while (size > 0 && ret == 0) { tmp_size = size; - - spin_lock(&virt_entry->bind_lock); bind_obj = _find_containing_bind_obj(virt_entry, offset, size); - - if (bind_obj == NULL) { - spin_unlock(&virt_entry->bind_lock); + if (bind_obj == NULL) return 0; - } if (bind_obj->v_off > offset) { tmp_size = size - bind_obj->v_off - offset; @@ -3611,28 +3624,7 @@ static long sparse_unbind_range(struct kgsl_sparse_binding_object *obj, tmp_size = bind_obj->size; } - memdesc = bind_obj->p_memdesc; - pt = memdesc->pagetable; - - if (memdesc->cur_bindings < (tmp_size / PAGE_SIZE)) { - spin_unlock(&virt_entry->bind_lock); - return -EINVAL; - } - - memdesc->cur_bindings -= tmp_size / PAGE_SIZE; - ret = _sparse_unbind(virt_entry, bind_obj, offset, tmp_size); - spin_unlock(&virt_entry->bind_lock); - - ret = kgsl_mmu_unmap_offset(pt, memdesc, - virt_entry->memdesc.gpuaddr, offset, tmp_size); - if (ret) - return ret; - - ret = kgsl_mmu_sparse_dummy_map(pt, memdesc, offset, tmp_size); - if (ret) - return ret; - if (ret == 0) { offset += tmp_size; size -= tmp_size; @@ -4405,13 +4397,13 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr, if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) { val = get_unmapped_area(NULL, addr, len, 0, flags); if (IS_ERR_VALUE(val)) - KGSL_DRV_ERR_RATELIMIT(device, + KGSL_MEM_ERR(device, "get_unmapped_area: pid %d addr %lx pgoff %lx len %ld failed error %d\n", private->pid, addr, pgoff, len, (int) val); } else { val = _get_svm_area(private, entry, addr, len, flags); if (IS_ERR_VALUE(val)) - KGSL_DRV_ERR_RATELIMIT(device, + KGSL_MEM_ERR(device, "_get_svm_area: pid %d mmap_base %lx addr %lx pgoff %lx len %ld failed error %d\n", private->pid, current->mm->mmap_base, addr, pgoff, len, (int) val); diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index faf38d1d2293725be3d079479a9ec43ca0854846..fe62542ea01592c56c2c53f50ce6a55112cd2a7b 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2017, 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 @@ -51,7 +51,7 @@ /* The number of memstore arrays limits the number of contexts allowed. * If more contexts are needed, update multiple for MEMSTORE_SIZE */ -#define KGSL_MEMSTORE_SIZE ((int)(PAGE_SIZE * 2)) +#define KGSL_MEMSTORE_SIZE ((int)(PAGE_SIZE * 8)) #define KGSL_MEMSTORE_GLOBAL (0) #define KGSL_PRIORITY_MAX_RB_LEVELS 4 #define KGSL_MEMSTORE_MAX (KGSL_MEMSTORE_SIZE / \ diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c index fba18231cb7238bc91dde1056040c5cd617b6edd..f8f0e7ccb0d384770c34a96bc20a3aa6a71c3fd6 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_drawobj.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -79,7 +79,6 @@ void kgsl_dump_syncpoints(struct kgsl_device *device, { struct kgsl_drawobj_sync_event *event; unsigned int i; - unsigned long flags; for (i = 0; i < syncobj->numsyncs; i++) { event = &syncobj->synclist[i]; @@ -102,16 +101,12 @@ void kgsl_dump_syncpoints(struct kgsl_device *device, break; } case KGSL_CMD_SYNCPOINT_TYPE_FENCE: - spin_lock_irqsave(&event->handle_lock, flags); - if (event->handle) dev_err(device->dev, " fence: [%pK] %s\n", event->handle->fence, event->handle->name); else dev_err(device->dev, " fence: invalid\n"); - - spin_unlock_irqrestore(&event->handle_lock, flags); break; } } @@ -124,7 +119,6 @@ static void syncobj_timer(unsigned long data) struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj); struct kgsl_drawobj_sync_event *event; unsigned int i; - unsigned long flags; if (syncobj == NULL || drawobj->context == NULL) return; @@ -153,16 +147,12 @@ static void syncobj_timer(unsigned long data) i, event->context->id, event->timestamp); break; case KGSL_CMD_SYNCPOINT_TYPE_FENCE: - spin_lock_irqsave(&event->handle_lock, flags); - if (event->handle != NULL) { dev_err(device->dev, " [%d] FENCE %s\n", i, event->handle->fence ? event->handle->fence->name : "NULL"); kgsl_sync_fence_log(event->handle->fence); } - - spin_unlock_irqrestore(&event->handle_lock, flags); break; } } @@ -241,7 +231,7 @@ static void drawobj_destroy_sparse(struct kgsl_drawobj *drawobj) static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) { struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj); - unsigned long pending, flags; + unsigned long pending; unsigned int i; /* Zap the canary timer */ @@ -272,17 +262,8 @@ static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) drawobj_sync_func, event); break; case KGSL_CMD_SYNCPOINT_TYPE_FENCE: - spin_lock_irqsave(&event->handle_lock, flags); - - if (kgsl_sync_fence_async_cancel(event->handle)) { - event->handle = NULL; - spin_unlock_irqrestore( - &event->handle_lock, flags); + if (kgsl_sync_fence_async_cancel(event->handle)) drawobj_put(drawobj); - } else { - spin_unlock_irqrestore( - &event->handle_lock, flags); - } break; } } @@ -344,23 +325,12 @@ EXPORT_SYMBOL(kgsl_drawobj_destroy); static void drawobj_sync_fence_func(void *priv) { - unsigned long flags; struct kgsl_drawobj_sync_event *event = priv; - drawobj_sync_expire(event->device, event); - trace_syncpoint_fence_expire(event->syncobj, event->handle ? event->handle->name : "unknown"); - spin_lock_irqsave(&event->handle_lock, flags); - - /* - * Setting the event->handle to NULL here make sure that - * other function does not dereference a invalid pointer. - */ - event->handle = NULL; - - spin_unlock_irqrestore(&event->handle_lock, flags); + drawobj_sync_expire(event->device, event); drawobj_put(&event->syncobj->base); } @@ -378,14 +348,7 @@ static int drawobj_add_sync_fence(struct kgsl_device *device, struct kgsl_cmd_syncpoint_fence *sync = priv; struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj); struct kgsl_drawobj_sync_event *event; - struct sync_fence *fence = NULL; unsigned int id; - unsigned long flags; - int ret = 0; - - fence = sync_fence_fdget(sync->fd); - if (fence == NULL) - return -EINVAL; kref_get(&drawobj->refcount); @@ -399,39 +362,32 @@ static int drawobj_add_sync_fence(struct kgsl_device *device, event->device = device; event->context = NULL; - spin_lock_init(&event->handle_lock); set_bit(event->id, &syncobj->pending); - trace_syncpoint_fence(syncobj, fence->name); - - spin_lock_irqsave(&event->handle_lock, flags); - event->handle = kgsl_sync_fence_async_wait(sync->fd, drawobj_sync_fence_func, event); if (IS_ERR_OR_NULL(event->handle)) { - ret = PTR_ERR(event->handle); - - event->handle = NULL; - spin_unlock_irqrestore(&event->handle_lock, flags); + int ret = PTR_ERR(event->handle); clear_bit(event->id, &syncobj->pending); + event->handle = NULL; drawobj_put(drawobj); /* - * Print a syncpoint_fence_expire trace if - * the fence is already signaled or there is - * a failure in registering the fence waiter. + * If ret == 0 the fence was already signaled - print a trace + * message so we can track that */ - trace_syncpoint_fence_expire(syncobj, (ret < 0) ? - "error" : fence->name); - } else { - spin_unlock_irqrestore(&event->handle_lock, flags); + if (ret == 0) + trace_syncpoint_fence_expire(syncobj, "signaled"); + + return ret; } - sync_fence_put(fence); - return ret; + trace_syncpoint_fence(syncobj, event->handle->name); + + return 0; } /* drawobj_add_sync_timestamp() - Add a new sync point for a sync obj diff --git a/drivers/gpu/msm/kgsl_drawobj.h b/drivers/gpu/msm/kgsl_drawobj.h index b208870e4c4244dc752af8a262d93a33fa3838b9..fd9d2bc93f41ae8bffc4a254319dbe46886a5701 100644 --- a/drivers/gpu/msm/kgsl_drawobj.h +++ b/drivers/gpu/msm/kgsl_drawobj.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 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 @@ -114,7 +114,6 @@ struct kgsl_drawobj_sync { * register this event * @timestamp: Pending timestamp for the event * @handle: Pointer to a sync fence handle - * @handle_lock: Spin lock to protect handle * @device: Pointer to the KGSL device */ struct kgsl_drawobj_sync_event { @@ -124,7 +123,6 @@ struct kgsl_drawobj_sync_event { struct kgsl_context *context; unsigned int timestamp; struct kgsl_sync_fence_waiter *handle; - spinlock_t handle_lock; struct kgsl_device *device; }; diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h index 9b7833bdb2dfcac5e38277f8abeb06a81e1887e7..51baabefb6d3aaed902c006849c72a0eb789e9e3 100644 --- a/drivers/gpu/msm/kgsl_log.h +++ b/drivers/gpu/msm/kgsl_log.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2008-2011,2013-2014,2016-2017 The Linux Foundation. +/* Copyright (c) 2002,2008-2011,2013-2014,2016 The Linux Foundation. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -67,13 +67,6 @@ __func__, ##args);\ } while (0) -#define KGSL_LOG_ERR_RATELIMITED(dev, lvl, fmt, args...) \ - do { \ - if ((lvl) >= 3) \ - dev_err_ratelimited(dev, "|%s| " fmt, \ - __func__, ##args);\ - } while (0) - #define KGSL_DRV_INFO(_dev, fmt, args...) \ KGSL_LOG_INFO(_dev->dev, _dev->drv_log, fmt, ##args) #define KGSL_DRV_WARN(_dev, fmt, args...) \ @@ -84,8 +77,6 @@ KGSL_LOG_ERR(_dev->dev, _dev->drv_log, fmt, ##args) KGSL_LOG_CRIT(_dev->dev, _dev->drv_log, fmt, ##args) #define KGSL_DRV_CRIT_RATELIMIT(_dev, fmt, args...) \ KGSL_LOG_CRIT_RATELIMITED(_dev->dev, _dev->drv_log, fmt, ##args) -#define KGSL_DRV_ERR_RATELIMIT(_dev, fmt, args...) \ -KGSL_LOG_ERR_RATELIMITED(_dev->dev, _dev->drv_log, fmt, ##args) #define KGSL_DRV_FATAL(_dev, fmt, args...) \ KGSL_LOG_FATAL((_dev)->dev, (_dev)->drv_log, fmt, ##args) diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c index 685ce3ea968ba35753791a374fe42e859602b639..c31a85b07447b93187b25654c2ed186c53823381 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.c @@ -65,19 +65,26 @@ _kgsl_get_pool_from_order(unsigned int order) /* Map the page into kernel and zero it out */ static void -_kgsl_pool_zero_page(struct page *p) +_kgsl_pool_zero_page(struct page *p, unsigned int pool_order) { - void *addr = kmap_atomic(p); + int i; + + for (i = 0; i < (1 << pool_order); i++) { + struct page *page = nth_page(p, i); + void *addr = kmap_atomic(page); - memset(addr, 0, PAGE_SIZE); - dmac_flush_range(addr, addr + PAGE_SIZE); - kunmap_atomic(addr); + memset(addr, 0, PAGE_SIZE); + dmac_flush_range(addr, addr + PAGE_SIZE); + kunmap_atomic(addr); + } } /* Add a page to specified pool */ static void _kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p) { + _kgsl_pool_zero_page(p, pool->pool_order); + spin_lock(&pool->list_lock); list_add_tail(&p->lru, &pool->page_list); pool->page_count++; @@ -322,6 +329,7 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, } else return -ENOMEM; } + _kgsl_pool_zero_page(page, order); goto done; } @@ -341,6 +349,7 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, page = alloc_pages(gfp_mask, order); if (page == NULL) return -ENOMEM; + _kgsl_pool_zero_page(page, order); goto done; } } @@ -370,12 +379,13 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, } else return -ENOMEM; } + + _kgsl_pool_zero_page(page, order); } done: for (j = 0; j < (*page_size >> PAGE_SHIFT); j++) { p = nth_page(page, j); - _kgsl_pool_zero_page(p); pages[pcount] = p; pcount++; } diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 8c998a5d791b0e300cc60e6adad188b03ac07a2b..ad8b0131bb469cf69e8f19090595f20680f2cd61 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -43,6 +43,13 @@ #define DEFAULT_BUS_P 25 +/* + * The effective duration of qos request in usecs. After + * timeout, qos request is cancelled automatically. + * Kept 80ms default, inline with default GPU idle time. + */ +#define KGSL_L2PC_CPU_TIMEOUT (80 * 1000) + /* Order deeply matters here because reasons. New entries go on the end */ static const char * const clocks[] = { "src_clk", @@ -513,14 +520,12 @@ EXPORT_SYMBOL(kgsl_pwrctrl_set_constraint); /** * kgsl_pwrctrl_update_l2pc() - Update existing qos request * @device: Pointer to the kgsl_device struct - * @timeout_us: the effective duration of qos request in usecs. * * Updates an existing qos request to avoid L2PC on the * CPUs (which are selected through dtsi) on which GPU * thread is running. This would help for performance. */ -void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device, - unsigned long timeout_us) +void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device) { int cpu; @@ -534,7 +539,7 @@ void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device, pm_qos_update_request_timeout( &device->pwrctrl.l2pc_cpus_qos, device->pwrctrl.pm_qos_cpu_mask_latency, - timeout_us); + KGSL_L2PC_CPU_TIMEOUT); } } EXPORT_SYMBOL(kgsl_pwrctrl_update_l2pc); @@ -2196,10 +2201,6 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) kgsl_property_read_u32(device, "qcom,l2pc-cpu-mask", &pwr->l2pc_cpus_mask); - pwr->l2pc_update_queue = of_property_read_bool( - device->pdev->dev.of_node, - "qcom,l2pc-update-queue"); - pm_runtime_enable(&pdev->dev); ocmem_bus_node = of_find_node_by_name( diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 02707c901839d1829684f3b895823302ce70fdc1..42f918b80fcdc9b2412ea241889a9d042d55fbf9 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -51,19 +51,6 @@ #define KGSL_PWR_DEL_LIMIT 1 #define KGSL_PWR_SET_LIMIT 2 -/* - * The effective duration of qos request in usecs at queue time. - * After timeout, qos request is cancelled automatically. - * Kept 80ms default, inline with default GPU idle time. - */ -#define KGSL_L2PC_QUEUE_TIMEOUT (80 * 1000) - -/* - * The effective duration of qos request in usecs at wakeup time. - * After timeout, qos request is cancelled automatically. - */ -#define KGSL_L2PC_WAKEUP_TIMEOUT (10 * 1000) - enum kgsl_pwrctrl_timer_type { KGSL_PWR_IDLE_TIMER, }; @@ -141,12 +128,10 @@ struct kgsl_regulator { * @irq_name - resource name for the IRQ * @clk_stats - structure of clock statistics * @l2pc_cpus_mask - mask to avoid L2PC on masked CPUs - * @l2pc_update_queue - Boolean flag to avoid L2PC on masked CPUs at queue time * @l2pc_cpus_qos - qos structure to avoid L2PC on CPUs * @pm_qos_req_dma - the power management quality of service structure * @pm_qos_active_latency - allowed CPU latency in microseconds when active * @pm_qos_cpu_mask_latency - allowed CPU mask latency in microseconds - * @input_disable - To disable GPU wakeup on touch input event * @pm_qos_wakeup_latency - allowed CPU latency in microseconds during wakeup * @bus_control - true if the bus calculation is independent * @bus_mod - modifier from the current power level for the bus vote @@ -198,13 +183,11 @@ struct kgsl_pwrctrl { const char *irq_name; struct kgsl_clk_stats clk_stats; unsigned int l2pc_cpus_mask; - bool l2pc_update_queue; struct pm_qos_request l2pc_cpus_qos; struct pm_qos_request pm_qos_req_dma; unsigned int pm_qos_active_latency; unsigned int pm_qos_cpu_mask_latency; unsigned int pm_qos_wakeup_latency; - bool input_disable; bool bus_control; int bus_mod; unsigned int bus_percent_ab; @@ -266,6 +249,5 @@ int kgsl_active_count_wait(struct kgsl_device *device, int count); void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy); void kgsl_pwrctrl_set_constraint(struct kgsl_device *device, struct kgsl_pwr_constraint *pwrc, uint32_t id); -void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device, - unsigned long timeout_us); +void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device); #endif /* __KGSL_PWRCTRL_H */ diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index 2b7a1fcbaa7808c0e385075a3db29511e83c5604..24a1a42af74eb9e9ef34d591c0b26b7d9dec433e 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -522,8 +522,7 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_pwrctrl *pwr; struct kgsl_pwrlevel *pwr_level; - int level; - unsigned int i; + int level, i; unsigned long cur_freq; if (device == NULL) @@ -552,11 +551,10 @@ int kgsl_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) if (*freq != cur_freq) { level = pwr->max_pwrlevel; /* - * Array index of pwrlevels[] should be within the permitted - * power levels, i.e., from max_pwrlevel to min_pwrlevel. + * To avoid infinite loop issue type cast max_pwrlevel to + * signed integer type */ - for (i = pwr->min_pwrlevel; (i >= pwr->max_pwrlevel - && i <= pwr->min_pwrlevel); i--) + for (i = pwr->min_pwrlevel; i >= (int)pwr->max_pwrlevel; i--) if (*freq <= pwr->pwrlevels[i].gpu_freq) { if (pwr->thermal_cycle == CYCLE_ACTIVE) level = _thermal_adjust(pwr, i); @@ -591,7 +589,7 @@ int kgsl_devfreq_get_dev_status(struct device *dev, struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_pwrctrl *pwrctrl; struct kgsl_pwrscale *pwrscale; - ktime_t tmp1, tmp2; + ktime_t tmp; if (device == NULL) return -ENODEV; @@ -602,8 +600,6 @@ int kgsl_devfreq_get_dev_status(struct device *dev, pwrctrl = &device->pwrctrl; mutex_lock(&device->mutex); - - tmp1 = ktime_get(); /* * If the GPU clock is on grab the latest power counter * values. Otherwise the most recent ACTIVE values will @@ -611,9 +607,9 @@ int kgsl_devfreq_get_dev_status(struct device *dev, */ kgsl_pwrscale_update_stats(device); - tmp2 = ktime_get(); - stat->total_time = ktime_us_delta(tmp2, pwrscale->time); - pwrscale->time = tmp1; + tmp = ktime_get(); + stat->total_time = ktime_us_delta(tmp, pwrscale->time); + pwrscale->time = tmp; stat->busy_time = pwrscale->accum_stats.busy_time; diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c index 4bf591c236a7dfbd31bb7c0ac71ae60f26fd02b5..358b3b0388994e6d76921620551b7e86c6b51c2b 100644 --- a/drivers/gpu/msm/kgsl_sync.c +++ b/drivers/gpu/msm/kgsl_sync.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -179,7 +179,7 @@ int kgsl_add_fence_event(struct kgsl_device *device, goto out; } snprintf(fence_name, sizeof(fence_name), - "%s-pid-%d-ctx-%d-ts-%u", + "%s-pid-%d-ctx-%d-ts-%d", device->name, current->group_leader->pid, context_id, timestamp); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 34ea83d067af21428b5954fa73b82bafb3a4a5b2..95d2770c7a037008757dabb55a490f113346e0bf 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -6,6 +6,11 @@ * Copyright (c) 2005 Michael Haboustak for Concept2, Inc * Copyright (c) 2006-2012 Jiri Kosina */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * This program is free software; you can redistribute it and/or modify it @@ -2011,6 +2016,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c7f8b70d15eeb1180ff7810807d1f4b9232c801d..24eef795a86db40249f08ab454cd3792ccd0826e 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -6,6 +6,11 @@ * Copyright (c) 2005 Michael Haboustak for Concept2, Inc * Copyright (c) 2006-2007 Jiri Kosina */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * This program is free software; you can redistribute it and/or modify it @@ -285,9 +290,6 @@ #define USB_VENDOR_ID_DEALEXTREAME 0x10c5 #define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a -#define USB_VENDOR_ID_DELL 0x413c -#define USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE 0x301a - #define USB_VENDOR_ID_DELORME 0x1163 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 #define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 @@ -869,6 +871,7 @@ #define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 #define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4 +#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 0x09cc #define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 21febbb0d84e6e59f9615cd9046d09b0690675f7..8e2bf78b51cc8c039a6347692fbb65b540ad0cc8 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -10,6 +10,11 @@ * Copyright (c) 2013 Colin Leitner * Copyright (c) 2014 Frank Praznik */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * This program is free software; you can redistribute it and/or modify it @@ -2277,6 +2282,11 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) hid_set_drvdata(hdev, sc); sc->hdev = hdev; + if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { + hid_dbg(hdev, "Ignoring DUALSHOCK4 Controller via USB\n"); + return 0; + } + ret = hid_parse(hdev); if (ret) { hid_err(hdev, "parse failed\n"); @@ -2404,6 +2414,11 @@ static void sony_remove(struct hid_device *hdev) { struct sony_sc *sc = hid_get_drvdata(hdev); + if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { + hid_dbg(hdev, "Ignoring DUALSHOCK4 Controller via USB\n"); + return; + } + if (sc->quirks & SONY_LED_SUPPORT) sony_leds_remove(sc); @@ -2458,6 +2473,8 @@ static const struct hid_device_id sony_devices[] = { /* Sony Dualshock 4 controllers for PS4 */ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER), .driver_data = DUALSHOCK4_CONTROLLER_USB }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2), + .driver_data = DUALSHOCK4_CONTROLLER_USB }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER), .driver_data = DUALSHOCK4_CONTROLLER_BT }, { } diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index d4d655a10df1804a2587fbd4170f7e4fc3af31bd..0b80633bae91ecb180a7b0d4d245a8dec6313e0d 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -364,15 +364,6 @@ static int i2c_hid_hwreset(struct i2c_client *client) if (ret) return ret; - /* - * The HID over I2C specification states that if a DEVICE needs time - * after the PWR_ON request, it should utilise CLOCK stretching. - * However, it has been observered that the Windows driver provides a - * 1ms sleep between the PWR_ON and RESET requests and that some devices - * rely on this. - */ - usleep_range(1000, 5000); - i2c_hid_dbg(ihid, "resetting...\n"); ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0); diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 690a9f0fa04293ff8b6ec617109a6e5dd08a34bc..9a32b318b763cace00d3f83d4e8404b4bead18f9 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -2,6 +2,11 @@ * User-space I/O driver support for HID subsystem * Copyright (c) 2012 David Herrmann */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index ce1543d69acbc7971b7b680f1574dc750220dfc1..6ca6ab00fa93ffdb57f288bd130ce13f2f89d040 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -72,7 +72,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL }, diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 700145b1508894f30a018aef278d15cfc458ef3a..da8fd9580223340a4ab9694fe237ff2974a0449e 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -510,13 +510,13 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, goto inval; field = report->field[uref->field_index]; + } - if (cmd == HIDIOCGCOLLECTIONINDEX) { - if (uref->usage_index >= field->maxusage) - goto inval; - } else if (uref->usage_index >= field->report_count) + if (cmd == HIDIOCGCOLLECTIONINDEX) { + if (uref->usage_index >= field->maxusage) goto inval; - } + } else if (uref->usage_index >= field->report_count) + goto inval; if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && (uref_multi->num_values > HID_MAX_MULTI_USAGES || diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c index 567fa0c360aec145c60e2bb41b9ffcaa9dd56f6d..1a1988ba21049636f9d208caade2b35770042dc8 100644 --- a/drivers/hwmon/qpnp-adc-common.c +++ b/drivers/hwmon/qpnp-adc-common.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -426,6 +431,44 @@ static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = { {44, 125} }; +/* Voltage to temperature */ +static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb_decidegc[] = { + {1758, -400}, + {1742, -350}, + {1719, -300}, + {1691, -250}, + {1654, -200}, + {1608, -150}, + {1551, -100}, + {1483, -50}, + {1404, 0}, + {1315, 50}, + {1218, 100}, + {1114, 150}, + {1007, 200}, + {900, 250}, + {795, 300}, + {696, 350}, + {605, 400}, + {522, 450}, + {448, 500}, + {383, 550}, + {327, 600}, + {278, 650}, + {237, 700}, + {202, 750}, + {172, 800}, + {146, 850}, + {125, 900}, + {107, 950}, + {92, 1000}, + {79, 1050}, + {68, 1100}, + {59, 1150}, + {51, 1200}, + {44, 1250} +}; + /* Voltage to temperature */ static const struct qpnp_vadc_map_pt adcmap_150k_104ef_104fb[] = { {1738, -40}, @@ -629,6 +672,47 @@ static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = { { 46, 125 }, }; +/* + * Voltage to temperature table for 100k pull up for NTCG104EF104 with + * 1.875V reference. + */ +static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb_1875_vref_decidegc[] = { + { 1831, -400 }, + { 1814, -350 }, + { 1791, -300 }, + { 1761, -250 }, + { 1723, -200 }, + { 1675, -150 }, + { 1616, -100 }, + { 1545, -50 }, + { 1463, 0 }, + { 1370, 50 }, + { 1268, 100 }, + { 1160, 150 }, + { 1049, 200 }, + { 937, 250 }, + { 828, 300 }, + { 726, 350 }, + { 630, 400 }, + { 544, 450 }, + { 467, 500 }, + { 399, 550 }, + { 340, 600 }, + { 290, 650 }, + { 247, 700 }, + { 209, 750 }, + { 179, 800 }, + { 153, 850 }, + { 130, 900 }, + { 112, 950 }, + { 96, 1000 }, + { 82, 1050 }, + { 71, 1100 }, + { 62, 1150 }, + { 53, 1200 }, + { 46, 1250 }, +}; + static int32_t qpnp_adc_map_voltage_temp(const struct qpnp_vadc_map_pt *pts, uint32_t tablesize, int32_t input, int64_t *output) { @@ -1186,6 +1270,161 @@ int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *chip, } EXPORT_SYMBOL(qpnp_adc_tm_scale_therm_voltage_pu2); +int32_t qpnp_adc_scale_therm_pu2_decidegc(struct qpnp_vadc_chip *chip, + int32_t adc_code, + const struct qpnp_adc_properties *adc_properties, + const struct qpnp_vadc_chan_properties *chan_properties, + struct qpnp_vadc_result *adc_chan_result) +{ + int64_t therm_voltage = 0; + int32_t rc = -EINVAL; + + if (!chip || !adc_properties || !chan_properties || !adc_chan_result || + !chan_properties->offset_gain_numerator || + !chan_properties->offset_gain_denominator) + goto error; + + if (adc_properties->adc_hc) { + /* (ADC code * vref_vadc (1.875V) * 1000) / (0x4000 * 1000) */ + if (adc_code > QPNP_VADC_HC_MAX_CODE) + adc_code = 0; + therm_voltage = (int64_t) adc_code; + therm_voltage *= (int64_t) (adc_properties->adc_vdd_reference + * 1000); + if (therm_voltage < 0) + goto error; + + therm_voltage = div64_s64(therm_voltage, + (QPNP_VADC_HC_VREF_CODE * 1000)); + + rc = qpnp_adc_map_voltage_temp( + adcmap_100k_104ef_104fb_1875_vref_decidegc, + ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref_decidegc), + therm_voltage, &adc_chan_result->physical); + } else { + qpnp_adc_scale_with_calib_param(adc_code, + adc_properties, chan_properties, &therm_voltage); + if (therm_voltage < 0) + goto error; + + if (chan_properties->calib_type == CALIB_ABSOLUTE) + do_div(therm_voltage, 1000); + + rc = qpnp_adc_map_voltage_temp( + adcmap_100k_104ef_104fb_decidegc, + ARRAY_SIZE(adcmap_100k_104ef_104fb_decidegc), + therm_voltage, &adc_chan_result->physical); + } + +error: + return rc; +} +EXPORT_SYMBOL(qpnp_adc_scale_therm_pu2_decidegc); + +int32_t qpnp_adc_tm_scale_voltage_therm_pu2_decidegc( + struct qpnp_vadc_chip *chip, + const struct qpnp_adc_properties *adc_properties, + uint32_t reg, int64_t *result) +{ + int64_t adc_voltage = 0; + struct qpnp_vadc_linear_graph param1; + int32_t rc = -EINVAL; + + if (!chip || !result || !adc_properties) + goto error; + + if (adc_properties->adc_hc) { + /* (ADC code * vref_vadc (1.875V)) / 0x4000 */ + if (reg > QPNP_VADC_HC_MAX_CODE) + reg = 0; + adc_voltage = (int64_t) reg; + adc_voltage *= QPNP_VADC_HC_VDD_REFERENCE_MV; + adc_voltage = div64_s64(adc_voltage, + QPNP_VADC_HC_VREF_CODE); + rc = qpnp_adc_map_voltage_temp( + adcmap_100k_104ef_104fb_1875_vref_decidegc, + ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref_decidegc), + adc_voltage, result); + } else { + rc = qpnp_get_vadc_gain_and_offset(chip, ¶m1, + CALIB_RATIOMETRIC); + if (rc) + goto error; + + adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref; + if (adc_voltage < 0) + adc_voltage = -adc_voltage; + + do_div(adc_voltage, param1.dy); + + rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb_decidegc, + ARRAY_SIZE(adcmap_100k_104ef_104fb_decidegc), + adc_voltage, result); + } + +error: + return rc; +} +EXPORT_SYMBOL(qpnp_adc_tm_scale_voltage_therm_pu2_decidegc); + +int32_t qpnp_adc_tm_scale_therm_voltage_pu2_decidegc( + struct qpnp_vadc_chip *chip, + const struct qpnp_adc_properties *adc_properties, + struct qpnp_adc_tm_config *param) +{ + struct qpnp_vadc_linear_graph param1; + int32_t rc = -EINVAL; + + if (!chip || !param || !adc_properties) + goto error; + + if (adc_properties->adc_hc) { + rc = qpnp_adc_map_temp_voltage( + adcmap_100k_104ef_104fb_1875_vref_decidegc, + ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref_decidegc), + param->low_thr_temp, ¶m->low_thr_voltage); + if (rc) + goto error; + param->low_thr_voltage *= QPNP_VADC_HC_VREF_CODE; + do_div(param->low_thr_voltage, QPNP_VADC_HC_VDD_REFERENCE_MV); + + rc = qpnp_adc_map_temp_voltage( + adcmap_100k_104ef_104fb_1875_vref_decidegc, + ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref_decidegc), + param->high_thr_temp, ¶m->high_thr_voltage); + if (rc) + goto error; + param->high_thr_voltage *= QPNP_VADC_HC_VREF_CODE; + do_div(param->high_thr_voltage, QPNP_VADC_HC_VDD_REFERENCE_MV); + } else { + qpnp_get_vadc_gain_and_offset(chip, ¶m1, CALIB_RATIOMETRIC); + + rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb_decidegc, + ARRAY_SIZE(adcmap_100k_104ef_104fb_decidegc), + param->low_thr_temp, ¶m->low_thr_voltage); + if (rc) + goto error; + + param->low_thr_voltage *= param1.dy; + do_div(param->low_thr_voltage, param1.adc_vref); + param->low_thr_voltage += param1.adc_gnd; + + rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb_decidegc, + ARRAY_SIZE(adcmap_100k_104ef_104fb_decidegc), + param->high_thr_temp, ¶m->high_thr_voltage); + if (rc) + goto error; + + param->high_thr_voltage *= param1.dy; + do_div(param->high_thr_voltage, param1.adc_vref); + param->high_thr_voltage += param1.adc_gnd; + } + +error: + return rc; +} +EXPORT_SYMBOL(qpnp_adc_tm_scale_therm_voltage_pu2_decidegc); + int32_t qpnp_adc_scale_therm_ncp03(struct qpnp_vadc_chip *chip, int32_t adc_code, const struct qpnp_adc_properties *adc_properties, diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c index 6ed947e5603bb6461edca5e67c82eb4a7944e59a..7b56f58135da0b7ed9b4a7ab1ed892e6de3ae5e6 100644 --- a/drivers/hwmon/qpnp-adc-voltage.c +++ b/drivers/hwmon/qpnp-adc-voltage.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -219,6 +224,7 @@ static struct qpnp_vadc_scale_fn vadc_scale_fn[] = { [SCALE_NCP_03WF683_THERM] = {qpnp_adc_scale_therm_ncp03}, [SCALE_QRD_SKUT1_BATT_THERM] = {qpnp_adc_scale_qrd_skut1_batt_therm}, [SCALE_PMI_CHG_TEMP] = {qpnp_adc_scale_pmi_chg_temp}, + [SCALE_THERM_100K_PULLUP_DECI] = {qpnp_adc_scale_therm_pu2_decidegc}, }; static struct qpnp_vadc_rscale_fn adc_vadc_rscale_fn[] = { diff --git a/drivers/hwtracing/coresight/coresight-remote-etm.c b/drivers/hwtracing/coresight/coresight-remote-etm.c index cc0b25b130d72d56dfd2ff540833914ce4641933..30b13282f6c024a22b5500e3a1fe6e9d9bf72a28 100644 --- a/drivers/hwtracing/coresight/coresight-remote-etm.c +++ b/drivers/hwtracing/coresight/coresight-remote-etm.c @@ -186,9 +186,12 @@ static void remote_etm_rcv_msg(struct work_struct *work) struct remote_etm_drvdata *drvdata = container_of(work, struct remote_etm_drvdata, work_rcv_msg); + mutex_lock(&drvdata->mutex); if (qmi_recv_msg(drvdata->handle) < 0) dev_err(drvdata->dev, "%s: Error receiving QMI message\n", __func__); + + mutex_unlock(&drvdata->mutex); } static void remote_etm_notify(struct qmi_handle *handle, diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 691c7bb3afac38f0ff03459319085ad7fc116378..316d8b783d941331375de9cbccb2e0ee7dac4435 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012, 2016-2017 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 @@ -764,16 +764,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) pm_runtime_get_sync(drvdata->dev); mutex_lock(&drvdata->mem_lock); - - spin_lock_irqsave(&drvdata->spinlock, flags); - if (drvdata->reading) { - spin_unlock_irqrestore(&drvdata->spinlock, flags); - mutex_unlock(&drvdata->mem_lock); - pm_runtime_put(drvdata->dev); - return -EBUSY; - } - spin_unlock_irqrestore(&drvdata->spinlock, flags); - if (drvdata->config_type == TMC_CONFIG_TYPE_ETR && drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) { /* @@ -817,8 +807,19 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) coresight_cti_map_trigout(drvdata->cti_flush, 1, 0); coresight_cti_map_trigin(drvdata->cti_reset, 2, 0); } + mutex_unlock(&drvdata->mem_lock); spin_lock_irqsave(&drvdata->spinlock, flags); + if (drvdata->reading) { + spin_unlock_irqrestore(&drvdata->spinlock, flags); + + if (drvdata->config_type == TMC_CONFIG_TYPE_ETR + && drvdata->out_mode == TMC_ETR_OUT_MODE_USB) + usb_qdss_close(drvdata->usbch); + pm_runtime_put(drvdata->dev); + + return -EBUSY; + } if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { tmc_etb_enable_hw(drvdata); @@ -844,7 +845,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) */ drvdata->sticky_enable = true; spin_unlock_irqrestore(&drvdata->spinlock, flags); - mutex_unlock(&drvdata->mem_lock); dev_info(drvdata->dev, "TMC enabled\n"); return 0; @@ -1140,7 +1140,6 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) unsigned long flags; enum tmc_mode mode; - mutex_lock(&drvdata->mem_lock); spin_lock_irqsave(&drvdata->spinlock, flags); if (!drvdata->sticky_enable) { dev_err(drvdata->dev, "enable tmc once before reading\n"); @@ -1173,13 +1172,11 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) out: drvdata->reading = true; spin_unlock_irqrestore(&drvdata->spinlock, flags); - mutex_unlock(&drvdata->mem_lock); dev_info(drvdata->dev, "TMC read start\n"); return 0; err: spin_unlock_irqrestore(&drvdata->spinlock, flags); - mutex_unlock(&drvdata->mem_lock); return ret; } @@ -1356,11 +1353,7 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, { struct tmc_drvdata *drvdata = container_of(file->private_data, struct tmc_drvdata, miscdev); - char *bufp; - - mutex_lock(&drvdata->mem_lock); - - bufp = drvdata->buf + *ppos; + char *bufp = drvdata->buf + *ppos; if (*ppos + len > drvdata->size) len = drvdata->size - *ppos; @@ -1382,7 +1375,6 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, if (copy_to_user(data, bufp, len)) { dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__); - mutex_unlock(&drvdata->mem_lock); return -EFAULT; } @@ -1390,8 +1382,6 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", __func__, len, (int)(drvdata->size - *ppos)); - - mutex_unlock(&drvdata->mem_lock); return len; } diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index f4ed71f9c1a7a85cabed519b49bd5abbe152a51f..c373ddebee00827a0e48ff38b481ac347c6e028b 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * I2C controller driver for Qualcomm Technologies Inc platforms */ @@ -409,6 +414,7 @@ struct i2c_msm_clk_div_fld { */ static struct i2c_msm_clk_div_fld i2c_msm_clk_div_map[] = { {KHz(100), 124, 62}, + {KHz(355), 32, 16}, {KHz(400), 28, 14}, {KHz(1000), 8, 5}, }; @@ -2232,8 +2238,19 @@ static int i2c_msm_pm_clk_enable(struct i2c_msm_ctrl *ctrl) static int i2c_msm_pm_xfer_start(struct i2c_msm_ctrl *ctrl) { int ret; + struct i2c_msm_xfer *xfer = &ctrl->xfer; mutex_lock(&ctrl->xfer.mtx); + /* if system is suspended just bail out */ + if (ctrl->pwr_state == I2C_MSM_PM_SYS_SUSPENDED) { + struct i2c_msg *msgs = xfer->msgs + xfer->cur_buf.msg_idx; + dev_err(ctrl->dev, + "slave:0x%x is calling xfer when system is suspended\n", + msgs->addr); + mutex_unlock(&ctrl->xfer.mtx); + return -EIO; + } + i2c_msm_pm_pinctrl_state(ctrl, true); pm_runtime_get_sync(ctrl->dev); /* @@ -2319,14 +2336,6 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) return PTR_ERR(msgs); } - /* if system is suspended just bail out */ - if (ctrl->pwr_state == I2C_MSM_PM_SYS_SUSPENDED) { - dev_err(ctrl->dev, - "slave:0x%x is calling xfer when system is suspended\n", - msgs->addr); - return -EIO; - } - ret = i2c_msm_pm_xfer_start(ctrl); if (ret) return ret; diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c index 28ab4e52dab5aa81282e337c3bf1ee8806279e2d..f0a1466defd8117d8bb43cf67eee883c0a0bff33 100644 --- a/drivers/iio/adc/qcom-rradc.c +++ b/drivers/iio/adc/qcom-rradc.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "RRADC: %s: " fmt, __func__ @@ -180,9 +185,6 @@ #define FG_ADC_RR_VOLT_INPUT_FACTOR 8 #define FG_ADC_RR_CURR_INPUT_FACTOR 2000 #define FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL 1886 -#define FG_ADC_RR_CURR_USBIN_660_FACTOR_MIL 9 -#define FG_ADC_RR_CURR_USBIN_660_UV_VAL 579500 - #define FG_ADC_SCALE_MILLI_FACTOR 1000 #define FG_ADC_KELVINMIL_CELSIUSMIL 273150 @@ -195,9 +197,6 @@ #define FG_RR_CONV_CONTINUOUS_TIME_MIN_US 50000 #define FG_RR_CONV_CONTINUOUS_TIME_MAX_US 51000 #define FG_RR_CONV_MAX_RETRY_CNT 50 -#define FG_RR_TP_REV_VERSION1 21 -#define FG_RR_TP_REV_VERSION2 29 -#define FG_RR_TP_REV_VERSION3 32 /* * The channel number is not a physical index in hardware, @@ -224,7 +223,22 @@ enum rradc_channel_id { RR_ADC_MAX }; +enum rradc_reg_data_idx { + RR_ADC_REG_DATA_ADDR = 0, + RR_ADC_REG_DATA_MASK, + RR_ADC_REG_DATA_VALUE, + RR_ADC_REG_DATA_IDX_MAX +}; + +struct rradc_reg_cfg { + uint32_t addr; + uint32_t mask; + uint32_t val; +}; + struct rradc_chip { + const struct rradc_reg_cfg *reg_cfg; + int reg_cfg_num; struct device *dev; struct mutex lock; struct regmap *regmap; @@ -234,7 +248,6 @@ struct rradc_chip { struct rradc_chan_prop *chan_props; struct device_node *revid_dev_node; struct pmic_revid_data *pmic_fab_id; - int volt; }; struct rradc_channels { @@ -360,7 +373,7 @@ static int rradc_post_process_volt(struct rradc_chip *chip, return 0; } -static int rradc_post_process_usbin_curr(struct rradc_chip *chip, +static int rradc_post_process_curr(struct rradc_chip *chip, struct rradc_chan_prop *prop, u16 adc_code, int *result_ua) { @@ -368,33 +381,11 @@ static int rradc_post_process_usbin_curr(struct rradc_chip *chip, if (!prop) return -EINVAL; - if (chip->revid_dev_node) { - switch (chip->pmic_fab_id->pmic_subtype) { - case PM660_SUBTYPE: - if (((chip->pmic_fab_id->tp_rev - >= FG_RR_TP_REV_VERSION1) - && (chip->pmic_fab_id->tp_rev - <= FG_RR_TP_REV_VERSION2)) - || (chip->pmic_fab_id->tp_rev - >= FG_RR_TP_REV_VERSION3)) { - chip->volt = div64_s64(chip->volt, 1000); - chip->volt = chip->volt * - FG_ADC_RR_CURR_USBIN_660_FACTOR_MIL; - chip->volt = FG_ADC_RR_CURR_USBIN_660_UV_VAL - - (chip->volt); - chip->volt = div64_s64(1000000000, chip->volt); - scale = chip->volt; - } else - scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL; - break; - case PMI8998_SUBTYPE: - scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL; - break; - default: - pr_err("No PMIC subtype found\n"); - return -EINVAL; - } - } + + if (prop->channel == RR_ADC_USBIN_I) + scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL; + else + scale = FG_ADC_RR_CURR_INPUT_FACTOR; /* scale * V/A; 2.5V ADC full scale */ ua = ((int64_t)adc_code * scale); @@ -405,24 +396,6 @@ static int rradc_post_process_usbin_curr(struct rradc_chip *chip, return 0; } -static int rradc_post_process_dcin_curr(struct rradc_chip *chip, - struct rradc_chan_prop *prop, u16 adc_code, - int *result_ua) -{ - int64_t ua = 0; - - if (!prop) - return -EINVAL; - - /* 0.5 V/A; 2.5V ADC full scale */ - ua = ((int64_t)adc_code * FG_ADC_RR_CURR_INPUT_FACTOR); - ua *= (FG_ADC_RR_FS_VOLTAGE_MV * FG_ADC_SCALE_MILLI_FACTOR); - ua = div64_s64(ua, (FG_MAX_ADC_READINGS * 1000)); - *result_ua = ua; - - return 0; -} - static int rradc_post_process_die_temp(struct rradc_chip *chip, struct rradc_chan_prop *prop, u16 adc_code, int *result_millidegc) @@ -638,13 +611,13 @@ static const struct rradc_channels rradc_chans[] = { BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED), FG_ADC_RR_SKIN_TEMP_LSB, FG_ADC_RR_SKIN_TEMP_MSB, FG_ADC_RR_AUX_THERM_STS) - RR_ADC_CHAN_CURRENT("usbin_i", &rradc_post_process_usbin_curr, + RR_ADC_CHAN_CURRENT("usbin_i", &rradc_post_process_curr, FG_ADC_RR_USB_IN_I_LSB, FG_ADC_RR_USB_IN_I_MSB, FG_ADC_RR_USB_IN_I_STS) RR_ADC_CHAN_VOLT("usbin_v", &rradc_post_process_volt, FG_ADC_RR_USB_IN_V_LSB, FG_ADC_RR_USB_IN_V_MSB, FG_ADC_RR_USB_IN_V_STS) - RR_ADC_CHAN_CURRENT("dcin_i", &rradc_post_process_dcin_curr, + RR_ADC_CHAN_CURRENT("dcin_i", &rradc_post_process_curr, FG_ADC_RR_DC_IN_I_LSB, FG_ADC_RR_DC_IN_I_MSB, FG_ADC_RR_DC_IN_I_STS) RR_ADC_CHAN_VOLT("dcin_v", &rradc_post_process_volt, @@ -1002,21 +975,6 @@ static int rradc_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_PROCESSED: - if (((chip->pmic_fab_id->tp_rev - >= FG_RR_TP_REV_VERSION1) - && (chip->pmic_fab_id->tp_rev - <= FG_RR_TP_REV_VERSION2)) - || (chip->pmic_fab_id->tp_rev - >= FG_RR_TP_REV_VERSION3)) { - if (chan->address == RR_ADC_USBIN_I) { - prop = &chip->chan_props[RR_ADC_USBIN_V]; - rc = rradc_do_conversion(chip, prop, &adc_code); - if (rc) - break; - prop->scale(chip, prop, adc_code, &chip->volt); - } - } - prop = &chip->chan_props[chan->address]; rc = rradc_do_conversion(chip, prop, &adc_code); if (rc) @@ -1049,6 +1007,8 @@ static const struct iio_info rradc_info = { static int rradc_get_dt_data(struct rradc_chip *chip, struct device_node *node) { + const uint32_t *prop_buf; + int reg_cfg_size = 0; const struct rradc_channels *rradc_chan; struct iio_chan_spec *iio_chan; unsigned int i = 0, base; @@ -1092,6 +1052,19 @@ static int rradc_get_dt_data(struct rradc_chip *chip, struct device_node *node) } } + prop_buf = of_get_property(node, "somc,reg-cfg", ®_cfg_size); + if (prop_buf) { + if ((reg_cfg_size / sizeof(uint32_t)) + % RR_ADC_REG_DATA_IDX_MAX) { + pr_err("Register config data is invalid size\n"); + return -EINVAL; + } + + chip->reg_cfg = (struct rradc_reg_cfg *)prop_buf; + chip->reg_cfg_num = reg_cfg_size / sizeof(uint32_t) + / RR_ADC_REG_DATA_IDX_MAX; + } + iio_chan = chip->iio_chans; for (i = 0; i < RR_ADC_MAX; i++) { @@ -1117,6 +1090,7 @@ static int rradc_get_dt_data(struct rradc_chip *chip, struct device_node *node) static int rradc_probe(struct platform_device *pdev) { + int i; struct device_node *node = pdev->dev.of_node; struct device *dev = &pdev->dev; struct iio_dev *indio_dev; @@ -1141,6 +1115,23 @@ static int rradc_probe(struct platform_device *pdev) if (rc) return rc; + for (i = 0; i < chip->reg_cfg_num; i++) { + rc = rradc_masked_write(chip, + (u16)be32_to_cpu(chip->reg_cfg[i].addr), + (u8)be32_to_cpu(chip->reg_cfg[i].mask), + (u8)be32_to_cpu(chip->reg_cfg[i].val)); + if (rc < 0) { + pr_err("Failed in register write (addr=0x%02x)\n", + (u16)be32_to_cpu(chip->reg_cfg[i].addr)); + return -EIO; + } + + pr_debug("Write register (addr=0x%02x mask=0x%02x value=0x%02x)\n", + (u16)be32_to_cpu(chip->reg_cfg[i].addr), + (u8)be32_to_cpu(chip->reg_cfg[i].mask), + (u8)be32_to_cpu(chip->reg_cfg[i].val)); + } + indio_dev->dev.parent = dev; indio_dev->dev.of_node = node; indio_dev->name = pdev->name; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 9eca4b41fa0ad080ca25c73e17afd7fe2634a1e1..1c02deab068fbf1031d5b21db960feb9b06865c5 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2287,10 +2287,6 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - if (cmd.port_num < rdma_start_port(ib_dev) || - cmd.port_num > rdma_end_port(ib_dev)) - return -EINVAL; - INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd, out_len); @@ -2831,10 +2827,6 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - if (cmd.attr.port_num < rdma_start_port(ib_dev) || - cmd.attr.port_num > rdma_end_port(ib_dev)) - return -EINVAL; - uobj = kmalloc(sizeof *uobj, GFP_KERNEL); if (!uobj) return -ENOMEM; diff --git a/drivers/input/input.c b/drivers/input/input.c index baaddd16880459160a75491981840b05caaecfde..61d9cb91d0e852952df130432e5f3c19b64d6d98 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -3,6 +3,11 @@ * * Copyright (c) 1999-2002 Vojtech Pavlik */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index c93dd193a496812465ec07b0cfb821e8201ea1e8..deaf0e5bc5252ab5c6b66d000507829d9dd7d4a6 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -9,6 +9,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index dd98d8c8fd1f3577b5de0ebbf12810e30903efc9..a0462aa4e4a568c24a824b7feb5ae977f0e0242c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -103,6 +103,15 @@ config INPUT_E3X0_BUTTON To compile this driver as a module, choose M here: the module will be called e3x0_button. +config INPUT_BU520X1NVX + tristate "BU520X1NVX driver support" + default n + help + Say Y here + if you want to + support BU520X1NVX + as bipolar detection device. + config INPUT_HBTP_INPUT tristate "HBTP input driver support" help @@ -844,4 +853,32 @@ config INPUT_STMVL53L0 To compile this driver as a module, choose M here: the module will be called stmvl53l0. +config FPC1145_PLATFORM + tristate "Platform FPC1145 finger print driver" + default n + help + Select this module to enable FPC1145 tee finger print driver + +config INPUT_ADUX1050 + tristate "ADUX1050 sensor support" + depends on I2C=y + help + Say Y here if you have ADUX1050 hooked to an I2C bus. + To compile this driver as a module, choose M here: + The module will be called adux1050.ko + +config ADUX1050_DEBUG + bool " Debug :To enable the Basic debug support for the driver" + depends on INPUT_ADUX1050 + default n + help + To add the basic debug support of the driver in the build. Used in printing the debug information on the console. + +config ADUX1050_EVAL + bool "Eval : To enable the driver in evaluation mode for test " + depends on INPUT_ADUX1050 + default n + help + To use the generic sysfs path and modifications for the control attributes. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 44c026abcb6fece1154c3ea3fe81bf717cb0f19f..c389e1b1282d914fc2e281457508a39690065081 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o obj-$(CONFIG_INPUT_AD714X) += ad714x.o obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o +obj-$(CONFIG_INPUT_ADUX1050) += adux1050.o obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o @@ -19,6 +20,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o obj-$(CONFIG_INPUT_BMA150) += bma150.o +obj-$(CONFIG_INPUT_BU520X1NVX) += bu520x1nvx.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o @@ -81,3 +83,4 @@ obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o obj-$(CONFIG_INPUT_PIXART_OTS_PAT9125_SWITCH) += ots_pat9125/ obj-$(CONFIG_INPUT_STMVL53L0) += vl53L0/ +obj-$(CONFIG_FPC1145_PLATFORM) += fpc1145_platform.o diff --git a/drivers/input/misc/adux1050.c b/drivers/input/misc/adux1050.c new file mode 100644 index 0000000000000000000000000000000000000000..d93e0aef30975c867a9a0532a61ac2a0a431ea40 --- /dev/null +++ b/drivers/input/misc/adux1050.c @@ -0,0 +1,4386 @@ +/* + * ADUX1050 Generic Controller Driver + * + * @copyright 2016 Analog Devices Inc. + * + * Licensed under the GPL version 2 or later. + * date OCT-2016 + * version Driver 1.3.1 + * version Linux 3.18.20 and above + * version Android 6.0.1 [Marshmallow] + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +/* + * drivers/input/misc/adux1050.c + * This file is the core driver part of ADUX1050 Capacitive sensor. + * It also has routines for interrupt handling, + * suspend, resume, initialization routines etc. + * + * ADUX1050 Generic Controller Driver + * + * Copyright 2016 Analog Devices Inc. + * + * Licensed under the GPL version 2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#endif +#ifdef CONFIG_ADUX1050_POLL +#include +#endif +#include + +#define ADUX1050_DRIVER_DBG(format, arg...) pr_debug("[ADUX1050]:"format,\ + ## arg) + +#ifdef CONFIG_ADUX1050_AWFUL_LOG +#define ADUX1050_AWFUL_LOG(format, arg...) pr_debug("[ADUX1050]:"format, ## arg) +#else +#define ADUX1050_AWFUL_LOG(format, arg...) do { if (0); } while (0) +#endif + + +#define CHK_AUTO_TH_ENABLED(bs_reg) (bs_reg & AUTO_TH_MASK) + + +/* + * Local platform data used if no platform data is found in board file or + * Device tree. + */ +static struct adux1050_platform_data local_plat_data = { + .init_regs = { + 0x0001010F, 0x00020529, 0x00030000, 0x00050F55, + 0x00069999, 0x000700e8, 0x00080200, 0x00090000, + 0x000a000C, 0x00798000, + 0x000b9999, 0x000c03e8, 0x000d0200, 0x000e0000, + 0x000f000C, 0x007a8000, + 0x00109999, 0x001105e8, 0x00120200, 0x00130000, + 0x0014000C, 0x007b8000, + 0x00159999, 0x001607e8, 0x00170200, 0x00180000, + 0x0019000C, 0x007c8000, + }, + .req_stg0_base = 10000, + .req_stg1_base = 20000, + .req_stg2_base = 30000, + .req_stg3_base = 40000, + .is_set_irq_gpio_no = false, + .proxy_enable = false, + .allowed_proxy_time = 20, + .max_proxy_count = 10, + .intr_err = 0, +}; + +/* + * int adux1050_i2c_write(struct device *dev, u8 reg, u16 *data, u16 data_cnt) + * Writes to the device register through I2C interface. + * Used to write the data to the I2C client's Register through the i2c protocol + * Used i2c_transfer api's for the bus transfer + * @param dev The i2c client's device structure + * @param reg The register address to be written + * @param data The data buffer which holds the data to be written to the device + * @param data_cnt The number of data to be written to the device from buffer. + * @return Number of messages transferred, default 2 + * + * @see adux1050_i2c_read + */ +static int adux1050_i2c_write(struct device *dev, u8 reg, + u16 *data, u16 data_cnt) +{ + + struct i2c_client *client = to_i2c_client(dev); + u8 device_addr = client->addr; + u16 loop_cnt = 0; + u8 tx[(MAX_ADUX1050_WR_LEN*sizeof(short)) + 1] = {0}; + u16 *head; + s32 ret = -EIO; + struct i2c_msg adux1050_wr_msg = { + .addr = device_addr, + .buf = (u8 *)tx, + .len = ((data_cnt*sizeof(data_cnt))+1), + .flags = 0, + }; + if (!data) + return -EINVAL; + tx[0] = reg; + head = (unsigned short *)&tx[1]; + for (loop_cnt = 0; loop_cnt < data_cnt; loop_cnt++) + *(head++) = cpu_to_be16(*(data++)); + + for (loop_cnt = 0; loop_cnt < I2C_RETRY_CNT; loop_cnt++) { + ret = i2c_transfer(client->adapter, &adux1050_wr_msg, 1); + if (unlikely(ret < 1)) + dev_err(&client->dev, "I2C write error %d\n", ret); + else + break; + } + return ret; +} + +/* + * int adux1050_i2c_read(struct device *dev, u8 reg,u16 *data, u16 data_cnt) + * This is used to read the data from the ADUX1050's register through + * I2C interface + * This function uses i2c protocol and its api's to read data from register + * @param dev The i2c client device Structure. + * @param reg The register address to be read. + * @param data The buffer's pointer to store the register's value. + * @param data_cnt The number of registers to be read. + * @return The number of messages transferred as an integer + * + * @see adux1050_i2c_write + */ +static int adux1050_i2c_read(struct device *dev, u8 reg, + u16 *data, u16 data_cnt) +{ + struct i2c_client *client = to_i2c_client(dev); + u16 loop_cnt = 0; + u16 rx[MAX_ADUX1050_WR_LEN] = {}; + s8 device_addr = client->addr; + s32 ret = 0; + struct i2c_msg adux1050_rd_msg[I2C_WRMSG_LEN] = { + { + .addr = device_addr, + .buf = (u8 *)®, + .len = sizeof(reg), + .flags = 0, + }, + { + .addr = device_addr, + .buf = (u8 *)rx, + .len = data_cnt * sizeof(short), + .flags = I2C_M_RD, + } + }; + for (loop_cnt = 0; loop_cnt < I2C_RETRY_CNT; loop_cnt++) { + ret = i2c_transfer(client->adapter, adux1050_rd_msg, + I2C_WRMSG_LEN); + if (unlikely(ret < I2C_WRMSG_LEN)) { + dev_err(dev, "[ADUX1050]: I2C READ error %d\n", ret); + if (loop_cnt >= (I2C_RETRY_CNT - 1)) + memset(data, 0, data_cnt * sizeof(short)); + } else { + for (loop_cnt = 0; loop_cnt < data_cnt; loop_cnt++) + data[loop_cnt] = be16_to_cpu(rx[loop_cnt]); + break; + } + } + return ret; +} + +/* + * inline u16 set_dac_offset(s16 new_offset_value) + * Function to set the DAC positive and negative offset based on given offset + * @param new_offset_value value to be set as the offset. + * @return Combined +ve and -ve value to be set to the DAC_OFFSET_STGx register + */ +static inline u16 set_dac_offset(s16 new_offset_value) +{ + u16 offset_val = 0; + + if (new_offset_value >= 0) + offset_val = ST_POS_DAC_OFFSET(new_offset_value); + else + offset_val = ST_NEG_DAC_OFFSET(new_offset_value); + + return offset_val; +} + +/* + * static inline s16 set_swap_state(struct adux1050_chip *adux1050, u16 stg_num, + * u16 *swap_state, s16 curr_val) + * Function to set the swap bits based on the calibration DAC offset + * @param adux1050 chip structure of ADUX1050 driver. + * @param stg_num The stage to which swap is to be done for DAC offset value. + * @param swap_state The swap state as set in control register + * [ctrl reg holds the swap state] + * @param curr_val Current value of DAC_offest for the stage provided [stg_num] + * @return Zero on success. + */ +static inline s16 set_swap_state(struct adux1050_chip *adux1050, u16 stg_num, + u16 *swap_state, s16 curr_val) { + s16 err = 0; + + if (!swap_state) + return -EINVAL; + if (curr_val > (MAX_OFFSET/2)) { + *swap_state = ((*swap_state & CLR_POS_SWAP) | SET_NEG_SWAP); + err = adux1050->write(adux1050->dev, GET_CONFIG_REG(stg_num), + swap_state, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Error in FC %d\n", err); + return err; + } + dev_dbg(adux1050->dev, "%s - Swap set %x", + __func__, *swap_state); + } else if (curr_val < -(MAX_OFFSET/2)) { + *swap_state = ((*swap_state & CLR_NEG_SWAP) | SET_POS_SWAP); + err = adux1050->write(adux1050->dev, GET_CONFIG_REG(stg_num), + swap_state, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Error in FC %d\n", err); + return err; + } + dev_dbg(adux1050->dev, "%s - Swap set %x", + __func__, *swap_state); + } else { + dev_dbg(adux1050->dev, "%s - No Swap to be set", __func__); + *swap_state = ((*swap_state & CLR_NEG_SWAP) & CLR_POS_SWAP); + err = adux1050->write(adux1050->dev, GET_CONFIG_REG(stg_num), + swap_state, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Error in FC %d\n", err); + return err; + } + } + return err; +} + +/* + * short adux1050_force_cal(struct adux1050_chip *adux1050,int cal_time) + * Internal function to perform force calibration of the Chip. + * @param adux1050 The chip structure of adux1050 driver + * @param cal_time Sleep time required after the force calibration. + * @return 0 on success and -1 on error + */ +static inline s16 adux1050_force_cal(struct adux1050_chip *adux1050, + int cal_time) +{ + u16 data = 0; + s16 err = 0; + + err = adux1050->read(adux1050->dev, BASELINE_CTRL_REG, &data, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Error in FC %d\n", err); + return -EIO; + } + data = data | FORCE_CAL_MASK; + err = adux1050->write(adux1050->dev, BASELINE_CTRL_REG, &data, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Error in FC %d\n", err); + return -EIO; + } + if (cal_time != 0) { + dev_dbg(adux1050->dev, " sleep time in FC:%d\n", cal_time); + msleep(cal_time); + } + return err; +} + +/* + * inline s16 get_conv_time(struct adux1050_chip *adux1050, int mul_flag) + * To get the required conversion time for the current seting + * @param adux1050 Chip structure. + * @param mul_flag Multiplier flag + * @return Returns the conversion time required for an updated configuration + */ +static inline s16 get_conv_time(struct adux1050_chip *adux1050, int mul_flag) +{ + u16 pwr_ctrl_reg = 0; + u16 cv_time_ctrl = 0; + u16 pwr_mode = 0; + u16 stg_num = 0; + u16 delay_in_ctoc = 0; + u16 avg = 0; + u16 osr = 0; + u16 phase = 0; + u16 base_time = 0; + u16 temp_base_time = 0; + u16 stg_cfg = 0; + u16 lp_cnt = 0; + s16 err = 0; + + err = adux1050->read(adux1050->dev, CTRL_REG, &pwr_ctrl_reg, DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, "i2c RD Err %d\n", err); + err = adux1050->read(adux1050->dev, CONV_TIME_CTRL_REG, &cv_time_ctrl, + DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, "i2c RD Err %d\n", err); + pwr_mode = GET_PWR_MODE(pwr_ctrl_reg); + stg_num = GET_NUM_STG(pwr_ctrl_reg); + adux1050->tot_stg = stg_num; + + if (pwr_mode == PWR_STAND_BY) { + dev_dbg(adux1050->dev, "Device in Standby mode\n"); + return 1; + } else if (pwr_mode == PWR_FULL_POWER) { + delay_in_ctoc = ZERO_VAL; + } else if (pwr_mode == PWR_TIMED_CONV) { + delay_in_ctoc = GET_TIMED_CONV_TIME(pwr_ctrl_reg); + } else if (pwr_mode == PWR_AUTO_WAKE) { + delay_in_ctoc = GET_TIMED_CONV_TIME(pwr_ctrl_reg); + if (delay_in_ctoc < GET_AUTO_WAKE_TIME(pwr_ctrl_reg)) + delay_in_ctoc = GET_AUTO_WAKE_TIME(pwr_ctrl_reg); + } + avg = GET_AVG_CONV(cv_time_ctrl); + avg = CALC_AVG_CONV(avg); /*AVG based multiplication factor*/ + osr = GET_OSR_CONV(cv_time_ctrl); + osr = CALC_OSR_CONV(osr); /*OSR multipling factor*/ + phase = GET_CONV_TIME(cv_time_ctrl); /*Phase timing factor*/ + /* Calculate base time as a factor of phase */ + temp_base_time = ((phase + (phase / DECIMAL_BASE)) - 3) / 2; + dev_dbg(adux1050->dev, "%s, temp_Basetime(%d), avg (%d), OSR (%d)\n", + __func__, temp_base_time, avg, osr); + temp_base_time *= (avg * osr); /*Set the base_time*/ + for (; lp_cnt < stg_num; lp_cnt++) { + err = adux1050->read(adux1050->dev, GET_CONFIG_REG(lp_cnt), + &stg_cfg, DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, "i2c RD Err %d\n", err); + if (IS_NOISE_MEASURE_EN(stg_cfg)) + base_time += (temp_base_time * + GET_NOISE_SAMPLE(cv_time_ctrl)); + else + base_time += temp_base_time; + } + if (mul_flag == TWICE_CONV_DELAY_TIME) { + base_time += base_time; /*Return twice the conv time*/ + base_time += delay_in_ctoc; /*Add the timed conv delay*/ + } else if (mul_flag == CONV_DELAY_TIME) { + base_time += delay_in_ctoc; + } + dev_dbg(adux1050->dev, "%s, Basetime(%d), delay_in_ctoc (%d)\n", + __func__, base_time, delay_in_ctoc); + + return base_time; +} + +/* + * int get_intr_mask_info(struct adux1050_chip *adux1050) + * This function is used to get interrupt mask information. + * @param adux1050 The chip structure of ADUX1050 driver + * @return 0 on success. + */ +static int get_intr_mask_info(struct adux1050_chip *adux1050) +{ + u16 temp_reg_val = 0; + s16 err = 0; + + /* Checking whether Conversion complete interrupt is enabled or not */ + err = adux1050->read(adux1050->dev, INT_CTRL_REG, + &temp_reg_val, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", err, __FILE__); + return err; + } + adux1050->conv_enable = CHECK_CONV_EN(temp_reg_val); + ADUX1050_DRIVER_DBG("%s - Checking conv_enable %d temp_reg_val %x\n", + __func__, adux1050->conv_enable, temp_reg_val); + /* Checking whether High threshold interrupt is enabled or not */ + adux1050->high_thresh_enable = CHECK_THRESH_HIGH_EN(temp_reg_val); + + /* Checking whether Low threshold interrupt is enabled or not */ + adux1050->low_thresh_enable = CHECK_THRESH_LOW_EN(temp_reg_val); + return 0; +} + +/* + * int getstageinfo(struct adux1050_chip *adux1050) + * This function is used to get the current stage information. + * @param adux1050 The chip structure of ADUX1050 driver + * @return 0 on success. + */ +static int getstageinfo(struct adux1050_chip *adux1050) +{ + u16 temp_reg_val = 0; + s16 err = 0; + u8 stg_cnt = 0; + u8 cin_cnt = 0; + u8 temp_cin; + + adux1050->conn_stg_cnt = 0; + + /* How many stages to measure CDC */ + err = adux1050->read(adux1050->dev, CTRL_REG, &temp_reg_val, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", err, __FILE__); + return err; + } + adux1050->num_stages = GET_NUM_STG(temp_reg_val); + /* Find whether stage is connected(either +ve or -ve) or not */ + for (stg_cnt = 0 ; stg_cnt < TOTAL_STG ; stg_cnt++) { + if (stg_cnt < adux1050->num_stages) { + err = adux1050->read(adux1050->dev, + GET_CONFIG_REG(stg_cnt), + &temp_reg_val, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", + err, __FILE__); + return err; + } + + adux1050->stg_info[stg_cnt].status = CIN_NOT_CONNECTED; + for (cin_cnt = 0; cin_cnt < TOTAL_CIN ; cin_cnt++) { + temp_cin = (temp_reg_val) & 3; + if ((temp_cin == CIN_NEG_INPUT) || + (temp_cin == CIN_POS_INPUT)) { + adux1050->stg_info[stg_cnt].status = + CIN_CONNECTED; + adux1050->conn_stg_cnt++; + dev_dbg(adux1050->dev, + "STG CONNECTED %d,tot=%d\n", + stg_cnt, + adux1050->conn_stg_cnt); + break; + } + temp_reg_val = temp_reg_val >> 2; + } + } else { + adux1050->stg_info[stg_cnt].status = CIN_NOT_CONNECTED; + pr_debug("%s - CDC not configured for STG_%d\n", + __func__, stg_cnt); + } + } + return 0; +} + +/* + * int update_calib_settings(struct adux1050_chip *adux1050, u16 total_stg, + u16 *data, bool write_to_reg, u8 file_exist) + * This function updates the calibration output to local register array and + registers of ADUX1050. + * @param adux1050 The chip structure of ADUX1050 driver + * @param total_stg Number of stages for which calib settings to be updated + * @param *data Pointer to buffer which contains the calib output + * @param write_to_reg A Flag to specify whether to write to registers or not + * @param file_exist A Flag to update the calib status + * @return 0 on success + */ +inline int update_calib_settings(struct adux1050_chip *adux1050, u16 total_stg, + u16 *data, bool write_to_reg, u8 file_exist) +{ + u16 temp_baseline_ctrl = 0; + u16 int_ctrl_reg = 0; + u16 stg_cnt = 0; + u16 stg_num = 0; + u8 fp = 0; + u16 cal_base_fail_flag = 0; + u16 value = 0; + u16 hys_reg = 0; + s16 err = 0; + + + /* Disable the interrupt */ + err = adux1050->read(adux1050->dev, INT_CTRL_REG, + &int_ctrl_reg, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", err, __FILE__); + goto err_calib; + } + value = int_ctrl_reg | DISABLE_DEV_INT; + err = adux1050->write(adux1050->dev, INT_CTRL_REG, &value, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", err, __FILE__); + goto err_calib; + } + + /* Disabling the Auto threhold & Force calib to */ + /* update baseline registers */ + err = adux1050->read(adux1050->dev, BASELINE_CTRL_REG, + &temp_baseline_ctrl, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", err, __FILE__); + goto err_calib; + } + temp_baseline_ctrl = temp_baseline_ctrl & ANTI_FORCE_CAL_MASK; + if (temp_baseline_ctrl & AUTO_TH_MASK) { + value = temp_baseline_ctrl; + value = value & (~AUTO_TH_MASK); + err = adux1050->write(adux1050->dev, BASELINE_CTRL_REG, + &value, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + goto err_calib; + } + } + msleep(adux1050->slp_time_conv_complete); + + for (stg_cnt = 0; stg_cnt < total_stg; stg_cnt++) { + stg_num = data[fp++]; + if ((stg_num >= STG_ZERO) && (stg_num <= STG_THREE)) { + + adux1050->pdata->cal_fact_base[stg_num] = data[fp++]; + adux1050->pdata->cal_offset[stg_num] = data[fp++]; + adux1050->pdata->digi_offset[stg_num] = data[fp++]; + adux1050->pdata->stg_cfg[stg_num] = data[fp++]; + + adux1050->bs_reg[stg_num].wr_flag = ADUX1050_ENABLE; + adux1050->bs_reg[stg_num].value = + adux1050->pdata->cal_fact_base[stg_num]; + + adux1050->reg[GET_OFFSET_REG(stg_num)].wr_flag = + ADUX1050_ENABLE; + adux1050->reg[GET_OFFSET_REG(stg_num)].value = + adux1050->pdata->cal_offset[stg_num]; + + adux1050->reg[GET_HYS_REG(stg_num)].wr_flag = + ADUX1050_ENABLE; + hys_reg = + ((adux1050->reg[GET_HYS_REG(stg_num)].value) & + HYS_BYTE_MASK) | + (adux1050->pdata->digi_offset[stg_num] << 8); + adux1050->reg[GET_HYS_REG(stg_num)].value = hys_reg; + + adux1050->reg[GET_CONFIG_REG(stg_num)].wr_flag = + ADUX1050_ENABLE; + adux1050->reg[GET_CONFIG_REG(stg_num)].value = + adux1050->pdata->stg_cfg[stg_num]; + cal_base_fail_flag |= + adux1050->pdata->cal_fact_base[stg_num]; + + if (write_to_reg == ADUX1050_ENABLE) { + err = adux1050->write( + adux1050->dev, GET_BASE_LINE_REG(stg_cnt), + &adux1050->pdata->cal_fact_base[stg_cnt], + DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, + "I2C WR Err %d in %s\n", + err, __FILE__); + goto err_calib; + } + + err = adux1050->write( + adux1050->dev, GET_OFFSET_REG(stg_cnt), + &adux1050->pdata->cal_offset[stg_cnt], DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, + "I2C WR Err %d in %s\n", + err, __FILE__); + goto err_calib; + } + + err = adux1050->read(adux1050->dev, + GET_HYS_REG(stg_cnt), + &hys_reg, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, + "I2C RD Err %d in %s\n", + err, __FILE__); + goto err_calib; + } + + hys_reg = + ((hys_reg & HYS_BYTE_MASK) | + (adux1050->pdata->digi_offset[stg_cnt] << 8)); + err = adux1050->write(adux1050->dev, + GET_HYS_REG(stg_cnt), + &hys_reg, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, + "I2C WR Err %d in %s\n", + err, __FILE__); + goto err_calib; + } + + err = adux1050->write( + adux1050->dev, GET_CONFIG_REG(stg_cnt), + &adux1050->pdata->stg_cfg[stg_cnt], DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, + "I2C WR Err %d in %s\n", + err, __FILE__); + goto err_calib; + } + } + + } else { + dev_err(adux1050->dev, + "%s Invalid Stg num in FILP or SYSFS input\n", + __func__); + break; + } + } + + pr_debug("Calib status = %d\n", adux1050->dac_calib.cal_flags); + /*Restoring the Auto threshold mode if enabled previously*/ + if (temp_baseline_ctrl & AUTO_TH_MASK) { + err = adux1050->write(adux1050->dev, BASELINE_CTRL_REG, + &temp_baseline_ctrl, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + goto err_calib; + } + } + /* Reenable the interrupt */ + err = adux1050->write(adux1050->dev, INT_CTRL_REG, + &int_ctrl_reg, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", err, __FILE__); + goto err_calib; + } + + if (cal_base_fail_flag != 0) { + adux1050->dac_calib.cal_flags = CAL_RET_SUCCESS; + #ifdef CONFIG_ADUX1050_EVAL + err = get_intr_mask_info(adux1050); + /* Getting the stage info */ + err = getstageinfo(adux1050); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, "Error in getstageinfo %d\n", + err); + goto err_calib; + } + #endif + } else { + if (file_exist) + adux1050->dac_calib.cal_flags = CAL_RET_EXIST; + else + adux1050->dac_calib.cal_flags = CAL_RET_NONE; + err = -EIO; + } + return err; +err_calib: + if (file_exist) + adux1050->dac_calib.cal_flags = CAL_RET_EXIST; + else + adux1050->dac_calib.cal_flags = CAL_RET_NONE; + err = -EIO; + return err; + +} + + +/* + * int adux1050_store_register_values(struct adux1050_chip *adux1050) + * This is to retrieve the register values from either device tree/local + * platform data and store it in local array + * @param adux1050 The Device structure + * @return Zero on success + */ +static int adux1050_store_register_values(struct adux1050_chip *adux1050) +{ + u32 lcnt = 0; + u32 data_cnt = 0; + const u32 *init_buffer = NULL; + const __be32 *df_regs = NULL; + u32 df_prop_length = 0; +#ifdef CONFIG_OF + + u32 len; + const __be32 *property = NULL; +#endif + u8 of_reg_found = false; + +#ifdef CONFIG_OF + + /* Fetching data from Device tree */ + if (adux1050->dt_device_node) { + df_regs = of_get_property(adux1050->dt_device_node, + "adi,adux1050_reg", &df_prop_length); + /* Fetching required baseline value for STG 0 */ + property = of_get_property(adux1050->dt_device_node, + "adi,adux1050_stg0_base", + &len); + if (property && len == sizeof(int)) { + adux1050->pdata->req_stg0_base = + be32_to_cpu(*property); + + dev_dbg(adux1050->dev, "valid req_base on %s\n", + adux1050->dt_device_node->full_name); + } else { + dev_dbg(adux1050->dev, "Invalid req_base on %s\n", + adux1050->dt_device_node->full_name); + } + /* Fetching required baseline value for STG 1 */ + property = of_get_property(adux1050->dt_device_node, + "adi,adux1050_stg1_base", + &len); + if (property && len == sizeof(int)) { + adux1050->pdata->req_stg1_base = + be32_to_cpu(*property); + + dev_dbg(adux1050->dev, "valid req_base1 on %s\n", + adux1050->dt_device_node->full_name); + } else { + dev_dbg(adux1050->dev, "Invalid req_base1 on %s\n", + adux1050->dt_device_node->full_name); + } + /* Fetching required baseline value for STG 2 */ + property = of_get_property(adux1050->dt_device_node, + "adi,adux1050_stg2_base", + &len); + if (property && len == sizeof(int)) { + adux1050->pdata->req_stg2_base = + be32_to_cpu(*property); + + dev_dbg(adux1050->dev, "valid req_base2 on %s\n", + adux1050->dt_device_node->full_name); + } else { + dev_dbg(adux1050->dev, "Invalid req_base2 on %s\n", + adux1050->dt_device_node->full_name); + } + /* Fetching required baseline value for STG 3 */ + property = of_get_property(adux1050->dt_device_node, + "adi,adux1050_stg3_base", &len); + if (property && len == sizeof(int)) { + adux1050->pdata->req_stg3_base = + be32_to_cpu(*property); + + dev_dbg(adux1050->dev, "valid req_base3 on %s\n", + adux1050->dt_device_node->full_name); + } else { + dev_dbg(adux1050->dev, "Invalid req_base3 on %s\n", + adux1050->dt_device_node->full_name); + } + } +#endif + if ((adux1050->pdata->req_stg0_base > MAX_CALIB_TARGET) || + (adux1050->pdata->req_stg0_base < MIN_CALIB_TARGET)) + adux1050->pdata->req_stg0_base = HALF_SCALE_VAL; + + if ((adux1050->pdata->req_stg1_base > MAX_CALIB_TARGET) || + (adux1050->pdata->req_stg1_base < MIN_CALIB_TARGET)) + adux1050->pdata->req_stg1_base = HALF_SCALE_VAL; + + if ((adux1050->pdata->req_stg2_base > MAX_CALIB_TARGET) || + (adux1050->pdata->req_stg2_base < MIN_CALIB_TARGET)) + adux1050->pdata->req_stg2_base = HALF_SCALE_VAL; + + if ((adux1050->pdata->req_stg3_base > MAX_CALIB_TARGET) || + (adux1050->pdata->req_stg3_base < MIN_CALIB_TARGET)) + adux1050->pdata->req_stg3_base = HALF_SCALE_VAL; + + /* Data from either DT or initial platform data */ + if ((!df_regs) || (df_prop_length % sizeof(u32))) { + if (df_prop_length % sizeof(u32)) + dev_err(adux1050->dev, "[ADUX1050]: Malformed prop regs\n"); + init_buffer = adux1050->pdata->init_regs; + data_cnt = sizeof(adux1050->pdata->init_regs)/sizeof(int); + } else { + init_buffer = df_regs; + data_cnt = df_prop_length / sizeof(u32); + of_reg_found = true; + } + /* Setting enable for INT_CTRL register */ + adux1050->reg[INT_CTRL_REG].wr_flag = ADUX1050_ENABLE; + + for (lcnt = 0; lcnt < data_cnt; lcnt++) { + u8 addr; + u16 value; + /* getting the address and the value to be written */ + if (likely(of_reg_found)) { + addr = (u8)((be32_to_cpu(init_buffer[lcnt]) + & ADDR_MASK) >> HEX_BASE); + value = (u16)(be32_to_cpu(init_buffer[lcnt]) + & DATA_MASK); + } else { + addr = (u8)((init_buffer[lcnt] & ADDR_MASK) + >> HEX_BASE); + value = (u16)(init_buffer[lcnt] & DATA_MASK); + } + /* Having a copy of device tree values in driver */ + if ((addr >= DEV_ID_REG) && + (addr <= HIGHEST_WR_ACCESS)) { + adux1050->reg[addr].wr_flag = ADUX1050_ENABLE; + adux1050->reg[addr].value = value; + /* pr_debug("!!!!!!! ADDR - %x ; VALUE - %x !!!!\n", */ + /* addr, adux1050->reg[addr].value);*/ + } + /* Copy of Baseline registers */ + if ((addr >= BASELINE_STG0_REG) && + (addr <= BASELINE_STG3_REG)) { + switch (addr) { + case BASELINE_STG0_REG: + adux1050->bs_reg[STG_ZERO].wr_flag = + ADUX1050_ENABLE; + adux1050->bs_reg[STG_ZERO].value = value; + break; + case BASELINE_STG1_REG: + adux1050->bs_reg[STG_ONE].wr_flag = + ADUX1050_ENABLE; + adux1050->bs_reg[STG_ONE].value = value; + break; + case BASELINE_STG2_REG: + adux1050->bs_reg[STG_TWO].wr_flag = + ADUX1050_ENABLE; + adux1050->bs_reg[STG_TWO].value = value; + break; + case BASELINE_STG3_REG: + adux1050->bs_reg[STG_THREE].wr_flag = + ADUX1050_ENABLE; + adux1050->bs_reg[STG_THREE].value = value; + } + } + } + + return 0; +} + +static void high_threshold_int_check(struct adux1050_chip *adux1050, + u16 high_status_change); + +/* if all RESULT_STGx is under BASELINE_STGx, do FORCE_CAL */ +static void adjust_baseline_after_enabled(struct adux1050_chip *adux1050) +{ + u8 stg_cnt = 0; + u16 result_cdc; + u16 baseline_cdc; + s16 err = 0; + bool do_force_cal = true; + + for (stg_cnt = 0; stg_cnt < adux1050->num_stages; stg_cnt++) { + /** Fetch the CDC only if that stage is connected */ + if (adux1050->stg_info[stg_cnt].status != CIN_CONNECTED) + continue; + err = adux1050->read(adux1050->dev, GET_RESULT_REG(stg_cnt), + &result_cdc, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C Read Error %d in %s", + err, __func__); + ADUX1050_DRIVER_DBG("RESULT_STG%d: 0x%04x\n", + stg_cnt, result_cdc); + err = adux1050->read(adux1050->dev, GET_BASE_LINE_REG(stg_cnt), + &baseline_cdc, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C Read Error %d in %s", + err, __func__); + if (result_cdc > baseline_cdc) + do_force_cal = false; + } + if (do_force_cal) + adux1050_force_cal(adux1050, adux1050->slp_time_conv_complete); +} + +/* + * int adux1050_hw_init(struct adux1050_chip *adux1050) + * To initialize the ADUX1050 device with register set defined in + * platform file or device tree + * @param adux1050 The Device structure + * @return Zero on success + */ +static int adux1050_hw_init(struct adux1050_chip *adux1050) +{ + u32 lcnt = 0; + u16 addr; + u16 slp_time = 0; + u16 temp_baseline_ctrl = 0; + u16 pwr_ctrl_buff = 0; + u16 temp_reg_value = 0; + u16 value = 0; + s16 err = 0; + + for (lcnt = 0; lcnt < (GLOBAL_REG_CNT + STG_CNF_CNT); lcnt++) { + addr = lcnt; + if (adux1050->reg[addr].wr_flag == ADUX1050_ENABLE) { + value = adux1050->reg[addr].value; + if (addr == BASELINE_CTRL_REG) { + value = value & ANTI_FORCE_CAL_MASK; + if (value & AUTO_TH_MASK) { + temp_baseline_ctrl = value; + value = value & (~AUTO_TH_MASK); + } + } else if (addr == CTRL_REG) { + value = value & ~RESET_MASK; + pwr_ctrl_buff = value; + value = SET_PWR_MODE(value, PWR_STAND_BY); + } else if (addr == INT_CTRL_REG) { + if (adux1050->int_pol == ACTIVE_HIGH) + adux1050->int_ctrl = + (value | ACTIVE_HIGH); + else + adux1050->int_ctrl = + (value & ~ACTIVE_HIGH); + value = adux1050->int_ctrl | DISABLE_DEV_INT; + } + ADUX1050_DRIVER_DBG("Addr %x Val %x\n", addr, value); + err = adux1050->write(adux1050->dev, addr, + &value, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + return err; + } + } + } + /* Baseline registers update */ + if (adux1050->bs_reg[STG_ZERO].wr_flag == ADUX1050_ENABLE) { + err = adux1050->write(adux1050->dev, BASELINE_STG0_REG, + &adux1050->bs_reg[STG_ZERO].value, + DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + return err; + } + } + if (adux1050->bs_reg[STG_ONE].wr_flag == ADUX1050_ENABLE) { + err = adux1050->write(adux1050->dev, BASELINE_STG1_REG, + &adux1050->bs_reg[STG_ONE].value, + DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + return err; + } + } + if (adux1050->bs_reg[STG_TWO].wr_flag == ADUX1050_ENABLE) { + err = adux1050->write(adux1050->dev, BASELINE_STG2_REG, + &adux1050->bs_reg[STG_TWO].value, + DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + return err; + } + } + if (adux1050->bs_reg[STG_THREE].wr_flag == ADUX1050_ENABLE) { + err = adux1050->write(adux1050->dev, BASELINE_STG3_REG, + &adux1050->bs_reg[STG_THREE].value, + DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + return err; + } + } + /* Restoring the power mode given in configuration */ + if (pwr_ctrl_buff) { + err = adux1050->write(adux1050->dev, CTRL_REG, + &pwr_ctrl_buff, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + return err; + } + slp_time = get_conv_time(adux1050, CONV_TIME); + if (slp_time > 0) + msleep(slp_time); + ADUX1050_DRIVER_DBG("Addr %x New Val %x\n", + CTRL_REG, pwr_ctrl_buff); + } + /* Auto threshold enable */ + if (temp_baseline_ctrl) { + err = adux1050->write(adux1050->dev, BASELINE_CTRL_REG, + &temp_baseline_ctrl, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + return err; + } + ADUX1050_DRIVER_DBG("Addr %x New Val %x\n", + BASELINE_CTRL_REG, + temp_baseline_ctrl); + } + /* Clearing the device interrupt STATUS register */ + err = adux1050->read(adux1050->dev, INT_STATUS_REG, + &temp_reg_value, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", err, __FILE__); + return err; + } + adux1050->prev_low_status = GET_LOW_STATUS(temp_reg_value); + adux1050->high_status = + adux1050->prev_high_status = GET_HIGH_STATUS(temp_reg_value); + + /* Report initial state before enabling interrupt */ + /* Note: high_thresh_enable is not set until we call getstageinfo() */ + adux1050->high_thresh_enable = CHECK_THRESH_HIGH_EN(adux1050->int_ctrl); + if (adux1050->high_thresh_enable) { + const u16 high_status_change = adux1050->high_thresh_enable; + + high_threshold_int_check(adux1050, high_status_change); + ADUX1050_DRIVER_DBG("Report Initial High State\n"); + } + + /* Getting the stage info */ + err = getstageinfo(adux1050); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, "Err in getstageinfo %d in %s\n", + err, __FILE__); + return err; + } + + /* Storing the sleeping time required for this configuration */ + adux1050->slp_time_conv_complete = get_conv_time(adux1050, + TWICE_CONV_DELAY_TIME); + dev_dbg(adux1050->dev, " CONV TIME: %d\n", + adux1050->slp_time_conv_complete); + + /* if all RESULT_STGx is under BASELINE_STGx, do FORCE_CAL */ + adjust_baseline_after_enabled(adux1050); + + /* Enabling the device interrupt */ + err = adux1050->write(adux1050->dev, INT_CTRL_REG, + &adux1050->int_ctrl, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", err, __FILE__); + return err; + } + ADUX1050_DRIVER_DBG("Addr %x New Val %x\n", + INT_CTRL_REG, adux1050->int_ctrl); + + err = get_intr_mask_info(adux1050); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, "Err in get_intr_mask_info %d in %s\n", + err, __FILE__); + return err; + } + + return 0; +} + +/* + * offset_write(struct adux1050_chip *adux1050, u16 stg_num, u16 data, + u16 slp_time) + * Internal function used to write the offset of the Stages + with a predeterminded delay + * @param adux1050 ADUX chip structure + * @param stg_num The stage to which offset has to be written + * @param data The Value to be written to the offset register + * @param slp_time Sleep time to given after writing the offset register + * @return write status is returned + */ +static int offset_write(struct adux1050_chip *adux1050, u16 stg_num, u16 data, + u16 slp_time) +{ + s32 ret = 0; + + ret = adux1050->write(adux1050->dev, GET_OFFSET_REG(stg_num), &data, + DEF_WR); + if (ret < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", ret, __FILE__); + return ret; + } + if (likely(slp_time)) + msleep(slp_time); + return ret; +} +/* + * inline s16 get_calc_dac_offset(u16 offset, u16 stg_cfg_reg) + * To calculate effective DAC offset value from pos & neg dac offset + * @param offset The current offset available. + * @param stg_cfg_reg The current stage configuration. + * @return the equivalant offset based on the swap bits. + */ +static inline s16 get_calc_dac_offset(u16 offset, u16 stg_cfg_reg) +{ + s16 cal_offset = 0; + + cal_offset = LD_POS_DAC_OFFSET(offset, stg_cfg_reg) + + LD_NEG_DAC_OFFSET(offset, stg_cfg_reg); + return cal_offset; +} + +/* + * inline int set_calc_dac_offset(struct adux1050_chip *adux1050, + s16 cal_offset, u16 stg_num, u16 *stg_cfg_reg, + u16 *offset, u16 sleep_time) + * Helper function to calculate the DAC offset for a stage. + * @param adux1050 Chip structure. + * @param cal_offset Calculated equalized offset + * @param stg_num Stage number + * @param *stg_cfg_reg Stage configuration register value. + * @param *offset Current offset set. + * @param sleep_time Sleep time required for register result cdc. + * @return Offset to be set to the register. +*/ +static inline int set_calc_dac_offset(struct adux1050_chip *adux1050, + s16 cal_offset, u16 stg_num, u16 *stg_cfg_reg, + u16 *offset, u16 sleep_time) +{ + s16 err = 0; + + if ((-MAX_OFFSET > cal_offset) || (cal_offset > MAX_OFFSET)) { + dev_err(adux1050->dev, "[ADUX1050]: %s, offset ERROR(%d)\n", + __func__, cal_offset); + return -EINVAL; + } + *offset = set_dac_offset(cal_offset); + err = set_swap_state(adux1050, stg_num, stg_cfg_reg, cal_offset); + if (err < 0) + return -EIO; + dev_dbg(adux1050->dev, "--->> %s, cal_off(%d)offset(%x) swap(%x)\n", + __func__, cal_offset, *offset, *stg_cfg_reg); + return offset_write(adux1050, stg_num, *offset, sleep_time); +} + +/* + * static int adux1050_offset_check(struct adux1050_chip *adux1050, + * u16 max_cnt, s16 dir_flag, u16 slp_time) + * ADUX1050 Saturation routine for bringing the device out of saturation using + directional hopping method + * @param adux1050 The device structure to be calibrated + * @param max_cnt Maximum count + * @param dir_flag Direction flag + * @param slp_time Sleep time to be given after offset check + * @return 0 if success or error on failure. + */ +static int adux1050_offset_check(struct adux1050_chip *adux1050, u16 max_cnt, + s16 dir_flag, u16 slp_time) +{ + s16 cal_offset; + u16 data; + u16 power_ctrl; + u16 cin_range; + u16 lp_count; + u16 stg_num; + u16 *offset; + u16 *stg_cfg_reg; + s16 err = 0; + + err = adux1050->read(adux1050->dev, CTRL_REG, &power_ctrl, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", err, __FILE__); + return err; + } + cin_range = GET_CIN_RANGE(power_ctrl); + adux1050->tot_stg = adux1050->num_stages; + for (lp_count = 0; lp_count < max_cnt ; lp_count++) { + for (stg_num = 0; stg_num < adux1050->tot_stg; stg_num++) { + if ((!CHECK_CAL_STATE( + adux1050->dac_calib.sat_comp_stat, stg_num)) || + (adux1050->stg_info[stg_num].status == + CIN_NOT_CONNECTED)) + continue; + offset = &adux1050->cur_dac_offset[stg_num]; + stg_cfg_reg = &adux1050->cur_swap_state[stg_num]; + err = adux1050->read(adux1050->dev, + GET_RESULT_REG(stg_num), + &data, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, + "I2C WR Err %d in %s\n", + err, __FILE__); + return err; + } + if ((data <= ZERO_SCALE_VALUE) || + (data >= FULL_SCALE_VALUE)) { + if (lp_count != 0) + cal_offset = get_calc_dac_offset( + *offset, *stg_cfg_reg); + else + cal_offset = 0; + cal_offset += + (GET_DAC_STEP_SIZE(DAC_CODEOUT_SAT, + cin_range) * dir_flag); + pr_debug("[%d]Curr offset set (%d)\n", + stg_num, cal_offset); + err = set_calc_dac_offset(adux1050, cal_offset, + stg_num, stg_cfg_reg, + offset, 0); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, + "set_calc_dac_offset failed %d\n", + err); + return err; + } + } else { + CLR_CAL_STATUS( + adux1050->dac_calib.sat_comp_stat, stg_num); + pr_debug("%s - SATUR state(%d)\n", __func__, + adux1050->dac_calib.sat_comp_stat); + if (!adux1050->dac_calib.sat_comp_stat) + goto adux_offset_ok; + } + ADUX1050_DRIVER_DBG("SATURATION STATUS - %x\n", + adux1050->dac_calib.sat_comp_stat); + } + msleep(slp_time); + } + return -EIO; +adux_offset_ok: + ADUX1050_DRIVER_DBG("%s, offset ok (%d)\n", __func__, data); + return 0; +} + +static inline void reset_stgcal_flag(struct adux1050_chip *adux1050, u16 *count) +{ + u16 lp_cnt = 0; + + for (; lp_cnt < adux1050->tot_stg; lp_cnt++) { + if (adux1050->stg_info[lp_cnt].status == CIN_CONNECTED) { + adux1050->dac_calib.stg_cal_stat |= (1 << lp_cnt); + count[lp_cnt] = 1; + } + } + +} +/* + * int adux1050_binary_offset_check(struct adux1050_chip *adux1050, + * u16 slp_time) + * ADUX1050 Saturation routine for bringing the device out of saturation using + * binary search method + * @param adux1050 The device structure to be calibrated + * @param slp_time Sleep time to be given after offset check + * @return Returns 0 on success and -EIO on error. + */ +static int adux1050_binary_offset_check(struct adux1050_chip *adux1050, + u16 slp_time) +{ + u16 data; + u16 lp_count; + u16 stg_num; + u16 *offset; + u16 *stg_cfg_reg; + s16 err = 0; + s16 low_dac_offset[TOTAL_STG] = {-MAX_OFFSET, + -MAX_OFFSET, + -MAX_OFFSET, + -MAX_OFFSET}; + s16 curr_dac_offset[TOTAL_STG] = {ZERO_VAL, + ZERO_VAL, + ZERO_VAL, + ZERO_VAL}; + s16 high_dac_offset[TOTAL_STG] = {MAX_OFFSET, + MAX_OFFSET, + MAX_OFFSET, + MAX_OFFSET}; + adux1050->tot_stg = adux1050->num_stages; + + for (lp_count = 0; lp_count < MAX_SEARCH_DEPTH ; lp_count++) { + for (stg_num = 0; stg_num < adux1050->tot_stg; stg_num++) { + if ((!CHECK_CAL_STATE( + adux1050->dac_calib.sat_comp_stat, stg_num)) || + (adux1050->stg_info[stg_num].status == + CIN_NOT_CONNECTED)) + continue; + offset = &adux1050->cur_dac_offset[stg_num]; + stg_cfg_reg = &adux1050->cur_swap_state[stg_num]; + err = adux1050->read(adux1050->dev, + GET_RESULT_REG(stg_num), &data, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C Read Err %d in %s\n", + err, __func__); + return err; + } + if (data >= FULL_SCALE_VALUE) { + low_dac_offset[stg_num] = + curr_dac_offset[stg_num]; + } else if (data <= ZERO_SCALE_VALUE) { + high_dac_offset[stg_num] = + curr_dac_offset[stg_num]; + } else { + CLR_CAL_STATUS( + adux1050->dac_calib.sat_comp_stat, + stg_num); + dev_dbg(adux1050->dev, + " SATUR state(%d)\n", + adux1050->dac_calib.sat_comp_stat); + if (!adux1050->dac_calib.sat_comp_stat) + goto adux_offset_ok; + + } + curr_dac_offset[stg_num] = (low_dac_offset[stg_num] + + high_dac_offset[stg_num]) / 2; + err = set_calc_dac_offset(adux1050, + curr_dac_offset[stg_num], + stg_num, stg_cfg_reg, + offset, 0); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, + "set_calc_dac_offset failed %d in %s\n", + err, __func__); + return err; + } + pr_debug("Offset Set for stg[%d]", stg_num); + pr_debug("Set to L[%d] C[%d] H[%d]", + low_dac_offset[stg_num], + curr_dac_offset[stg_num], + high_dac_offset[stg_num]); + } + msleep(slp_time); + } + err = adux1050->read(adux1050->dev, + GET_RESULT_REG(stg_num), + &data, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", err, __func__); + return err; + } + if (data <= ZERO_SCALE_VALUE || data >= FULL_SCALE_VALUE) { + pr_debug("offset_check- EIO"); + return -EIO; + } +adux_offset_ok: + pr_debug("offset ok (%d)", data); + return 0; +} + +/* + * do_dac_compensation(struct adux1050_chip *adux1050, u16 power_ctrl, + u16 cin_range, u16 *slp_time) + * Non saturation CDC compensation routine. + * @param adux1050 The device structure to be calibrated + * @param power_ctrl The power control register read + * @param cin_range The current configuration's CIN range value + * @param slp_time The sleep time to be given + */ +static int do_dac_compensation(struct adux1050_chip *adux1050, u16 power_ctrl, + u16 cin_range, u16 *slp_time) +{ + u16 cdc_diff; + u16 lp_count = 0; + u16 stg_num = 0; + u16 count[TOTAL_STG] = {0}; + s16 cal_offset = 0; + u16 flr_cnt = 0; + u16 data[TOTAL_STG] = {0}; + u16 hys_reg[TOTAL_STG] = {0}; + u16 offset = 0; + u16 stg_cfg_reg = 0; + s16 digi_offset = 0; + u16 use_digi_offset = 0; + s32 err = -EIO; + u16 u16_div = GET_ARB_DAC_STEP_SIZE(cin_range); + u16 dac_step = u16_div; + u16 trgt[TOTAL_STG] = {0}; + u16 init_swap_state[TOTAL_STG]; + u16 init_dac_offset[TOTAL_STG]; + struct adux1050_platform_data *pdata = adux1050->pdata; + u16 org_trgt[TOTAL_STG] = {pdata->req_stg0_base, + pdata->req_stg1_base, + pdata->req_stg2_base, + pdata->req_stg3_base}; + + *slp_time = get_conv_time(adux1050, TWICE_CONV_DELAY_TIME); + adux1050->dac_calib.sat_comp_stat = ZERO_VAL; + if (adux1050->metal_id >= MET_VER1) { + for (lp_count = 0; lp_count < TOTAL_STG; lp_count++) + trgt[lp_count] = org_trgt[lp_count]; + use_digi_offset = 1; + ADUX1050_DRIVER_DBG("%s Binary Search defined\n", __func__); + } + + /*Writing initial values to zero*/ + for (lp_count = 0; lp_count < adux1050->tot_stg; lp_count++) { + err = adux1050->read(adux1050->dev, GET_OFFSET_REG(lp_count), + &offset, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", + err, __FILE__); + goto calib_failed_break; + } + err = adux1050->read(adux1050->dev, GET_CONFIG_REG(lp_count), + &stg_cfg_reg, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", + err, __FILE__); + goto calib_failed_break; + } + init_swap_state[lp_count] = stg_cfg_reg; + init_dac_offset[lp_count] = offset; + /*Set initial step count to 1 WARNING: DO NOT set it to zero */ + count[lp_count] = 1; + cal_offset = get_calc_dac_offset(offset, stg_cfg_reg); + if (cal_offset != ZERO_VAL) + cal_offset = 0; + err = set_calc_dac_offset(adux1050, cal_offset, lp_count, + &stg_cfg_reg, &offset, 0); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, "CALC OFF ERR %d in %s\n", + err, __FILE__); + goto calib_failed_break; + } + adux1050->cur_swap_state[lp_count] = stg_cfg_reg; + adux1050->cur_dac_offset[lp_count] = offset; + if (adux1050->metal_id < MET_VER1) + trgt[lp_count] = HALF_SCALE_VAL; + /** Clear the Digital offset if set already*/ + err = adux1050->read(adux1050->dev, GET_HYS_REG(lp_count), + &hys_reg[lp_count], DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", + err, __FILE__); + goto calib_failed_break; + } + hys_reg[lp_count] &= HYS_BYTE_MASK; + err = adux1050->write(adux1050->dev, GET_HYS_REG(lp_count), + &hys_reg[lp_count], DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + goto calib_failed_break; + } + if (adux1050->stg_info[lp_count].status == CIN_CONNECTED) { + adux1050->dac_calib.sat_comp_stat |= (1 << lp_count); + adux1050->dac_calib.stg_cal_stat |= (1 << lp_count); + } + } + msleep(*slp_time); + u16_div = GET_ARB_DAC_STEP_SIZE(GET_CIN_RANGE(power_ctrl)); + dac_step = u16_div; + /* Clear the device from saturation*/ + if (adux1050->metal_id < MET_VER1) { + flr_cnt = (MAX_OFFSET / (GET_DAC_STEP_SIZE(DAC_CODEOUT_SAT, + GET_CIN_RANGE(power_ctrl)))); + ADUX1050_DRIVER_DBG("%s - POSITIVE SAT ROUTINE\n", __func__); + err = adux1050_offset_check(adux1050, flr_cnt, 1, *slp_time); + if (err < 0) { + ADUX1050_DRIVER_DBG("%s - NEGATIVE SAT ROUTINE\n", + __func__); + err = adux1050_offset_check(adux1050, flr_cnt, + MINUS_VAL, *slp_time); + if (err < 0) { + dev_err(adux1050->dev, + "adux1050_offset_chk fail %d in %s\n", + err, __func__); + goto calib_failed_break; + } + } + } else if (adux1050->metal_id >= MET_VER1) { + ADUX1050_DRIVER_DBG("%s - Binary SAT ROUTINE begins\n", + __func__); + err = adux1050_binary_offset_check(adux1050, *slp_time); + if (err < 0) { + dev_err(adux1050->dev, "%s - Fail for both directions", + __func__); + goto calib_failed_break; + } + dev_dbg(adux1050->dev, "%s - Binary SAT ROUTINE ends", + __func__); + } + /* Set Stage cal status to uncalibrated initial value*/ + + /* Make the stages to their corresponding target value*/ + for (lp_count = 0; lp_count < CALIB_LOOP_CNT; lp_count++) { + u16 prv_data; + + for (stg_num = 0; stg_num < adux1050->tot_stg; stg_num++) { + /*Skip the stage if already calibrated*/ + if ((!CHECK_CAL_STATE( + adux1050->dac_calib.stg_cal_stat, stg_num)) || + (adux1050->stg_info[stg_num].status == + CIN_NOT_CONNECTED)) + continue; + prv_data = data[stg_num]; + err = adux1050->read(adux1050->dev, + GET_RESULT_REG(stg_num), + &data[stg_num], DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, + "I2C RD Err %d in %s\n", + err, __FILE__); + goto calib_failed_break; + } + pr_debug("DATA %d,OFF %x,SWAP %x,STG %d\n", + data[stg_num], + adux1050->cur_dac_offset[stg_num], + adux1050->cur_swap_state[stg_num], + stg_num); + /*Device not in saturation*/ + cdc_diff = abs(data[stg_num] - trgt[stg_num]); + if (use_digi_offset && (cdc_diff < DIGI_OFFSET_SIZE)) { + count[stg_num] = 0; + } else { + u16_div = abs(prv_data - data[stg_num]); + u16_div = u16_div / count[stg_num]; + if ((u16_div < (dac_step/2)) || + (u16_div > (dac_step + dac_step))) + u16_div = dac_step; + dev_dbg(adux1050->dev, "%s,p_data(%d)", + __func__, prv_data); + flr_cnt = cdc_diff / u16_div; + count[stg_num] = ((cdc_diff % u16_div) > + GET_60_PERCENT(u16_div)) ? + (flr_cnt + 1) : flr_cnt; + pr_debug("FLC(%d),CNT(%d),DIV(%d),DIF(%d)\n", + flr_cnt, count[stg_num], + u16_div, cdc_diff); + } + if (count[stg_num] != 0) { + /* DAC step can be used to minimize the */ + /* difference in current and required CDC*/ + cal_offset = get_calc_dac_offset( + adux1050->cur_dac_offset[stg_num], + adux1050->cur_swap_state[stg_num]); + dev_dbg(adux1050->dev, "%s,cal_off %d\n", + __func__, cal_offset); + if (data[stg_num] > trgt[stg_num]) + cal_offset += count[stg_num]; + else + cal_offset -= count[stg_num]; + err = set_calc_dac_offset(adux1050, cal_offset, + stg_num, &adux1050->cur_swap_state[stg_num], + &adux1050->cur_dac_offset[stg_num], 0); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, "%s S_Off err\n", + __func__); + goto calib_failed_break; + } + } else { + CLR_CAL_STATUS( + adux1050->dac_calib.stg_cal_stat, stg_num); + /*When all the stages are in halfscale change*/ + /* to the original target and CIN_range*/ + if ((!adux1050->dac_calib.stg_cal_stat) && + (!use_digi_offset) && + (adux1050->metal_id < MET_VER1)) { + trgt[STG_ZERO] = pdata->req_stg0_base; + trgt[STG_ONE] = pdata->req_stg1_base; + trgt[STG_TWO] = pdata->req_stg2_base; + trgt[STG_THREE] = pdata->req_stg3_base; + pr_debug("R TRGT %x,%x,%x,%x\n", + trgt[STG_ZERO], trgt[STG_ONE], + trgt[STG_TWO], + trgt[STG_THREE]); + power_ctrl = SET_CIN_RANGE(power_ctrl, + cin_range); + err = adux1050->write(adux1050->dev, + CTRL_REG, &power_ctrl, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, + " I2C WR Err %d in %s\n", + err, __func__); + goto calib_failed_break; + } + u16_div = GET_ARB_DAC_STEP_SIZE( + GET_CIN_RANGE(power_ctrl)); + dac_step = u16_div; + reset_stgcal_flag(adux1050, count); + + use_digi_offset++; + /* msleep(*slp_time);*/ + break; + } + /*Not in saturation and DAC minimal step size*/ + /* is higher than the required correction*/ + digi_offset = GET_DIGI_OFFSET(trgt[stg_num], + data[stg_num]); + digi_offset = CLAMP_DIGI_OFFSET(digi_offset); + + adux1050->pdata->cal_offset[stg_num] = + adux1050->cur_dac_offset[stg_num]; + adux1050->pdata->digi_offset[stg_num] = + (u8)digi_offset; + + hys_reg[stg_num] = + ((hys_reg[stg_num] & HYS_BYTE_MASK) | + (adux1050->pdata->digi_offset[stg_num] << 8)); + err = adux1050->write(adux1050->dev, + GET_HYS_REG(stg_num), + &hys_reg[stg_num], DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, + "I2C WR Err %d in %s\n", + err, __func__); + goto calib_failed_break; + } + ADUX1050_DRIVER_DBG("Hys value = %x\n", + hys_reg[stg_num]); + msleep(*slp_time); + err = adux1050->read(adux1050->dev, + GET_RESULT_REG(stg_num), + &data[stg_num], DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, + "I2C RD Err %d in %s\n", + err, __func__); + goto calib_failed_break; + } + adux1050->pdata->cal_fact_base[stg_num] = + data[stg_num]; + adux1050->pdata->stg_cfg[stg_num] = + adux1050->cur_swap_state[stg_num]; + dev_dbg(adux1050->dev, + "bas(%d)off(%x)st_con(%x)dioff(%d)\n", + data[stg_num], offset, + stg_cfg_reg, digi_offset); + err = ZERO_VAL; + pr_debug("CAL STATUS - %x\n", + adux1050->dac_calib.stg_cal_stat); + if (!adux1050->dac_calib.stg_cal_stat) + goto calib_success_break; + else + continue; + } + } /*End of stage based loop*/ + msleep(*slp_time); + } /*End of for*/ + +calib_failed_break: + /*Failed to complete the compensation, return to the original values*/ + for (lp_count = 0; lp_count < adux1050->tot_stg; lp_count++) { + err = adux1050->write(adux1050->dev, GET_CONFIG_REG(lp_count), + &init_swap_state[lp_count], DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + err = adux1050->write(adux1050->dev, GET_OFFSET_REG(lp_count), + &init_dac_offset[lp_count], DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __FILE__); + adux1050->pdata->cal_fact_base[lp_count] = 0; + adux1050->pdata->cal_offset[lp_count] = 0; + adux1050->pdata->digi_offset[lp_count] = 0; + adux1050->pdata->stg_cfg[lp_count] = 0; + adux1050->dac_calib.cal_flags = CAL_RET_FAIL; + } + msleep(*slp_time); + return err; +calib_success_break: + adux1050->dac_calib.cal_flags = CAL_RET_SUCCESS; + return CAL_RET_SUCCESS; +} + +/* + * static inline int adux1050_disable(struct adux1050_chip *adux1050) + * Routine to set the power mode to standby in the ADUX1050 chip + * @param adux1050 Chip structure to set the power mode to shutdown + * @return Zero on success. + */ +static inline int adux1050_disable(struct adux1050_chip *adux1050) +{ + u16 data = 0; + s16 err = 0; + + mutex_lock(&adux1050->mutex); + err = adux1050->read(adux1050->dev, CTRL_REG, &data, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", err, __func__); + mutex_unlock(&adux1050->mutex); + return err; + } + if (GET_PWR_MODE(data) != PWR_STAND_BY) { + data = SET_PWR_MODE(data, PWR_STAND_BY); + err = adux1050->write(adux1050->dev, CTRL_REG, &data, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __func__); + mutex_unlock(&adux1050->mutex); + return err; + } + } + + mutex_unlock(&adux1050->mutex); + return 0; +} + +/* + * static int adux1050_enable(struct adux1050_chip *adux1050) + * Routine to set the driver to enable state in the ADUX1050 chip + * @param adux1050 Chip structure to set the power mode to shutdown + * @return Zero on success. + */ +static int adux1050_enable(struct adux1050_chip *adux1050) +{ + s16 err = 0; + + mutex_lock(&adux1050->mutex); + err = adux1050_hw_init(adux1050); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, "Failed in adux1050_hw_init %d\n", err); + mutex_unlock(&adux1050->mutex); + return err; + } + +#ifdef CONFIG_ADUX1050_EVAL + if (adux1050->power_mode_flag == ADUX1050_ENABLE) { + err = adux1050->write(adux1050->dev, CTRL_REG, + &adux1050->ctrl_reg, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d in %s\n", + err, __func__); + mutex_unlock(&adux1050->mutex); + return err; + } + adux1050->power_mode_flag = ADUX1050_DISABLE; + } +#endif + + mutex_unlock(&adux1050->mutex); + return 0; +} + +/* + * static void adux1050_calibration(struct work_struct *cal_work) + * ADUX1050 Calibration routine + * @param cal_work Pointer to "calib_work", member of ADUX1050 chip structure + * @return int + */ +static void adux1050_calibration(struct work_struct *cal_work) +{ + struct adux1050_chip *adux1050 = + container_of(cal_work, struct adux1050_chip, calib_work); + u8 slp_time_flag = 0; + s32 err = 0; + u16 data; + u16 power_ctrl; + u16 lp_cnt; + u16 slp_time = 0; + u16 s_t = 0; + u16 cv_time_ctrl = 0; + u16 cin_range = 0; + u16 cur_power = 0; + u32 start_time = jiffies; + + mutex_lock(&adux1050->mutex); + err = adux1050->read(adux1050->dev, INT_CTRL_REG, + &adux1050->dac_calib.enable_setting, DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + /* + * Disable interrupt and digital offset + */ + data = DISABLE_DEV_INT | adux1050->int_pol; + err = adux1050->write(adux1050->dev, INT_CTRL_REG, &data, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Err %d\n", err); + adux1050->dac_calib.cal_flags = CAL_RET_PENDING; + if (adux1050->dac_calib.action_flag) { + if (adux1050->proxy_enable) { + ADUX1050_DRIVER_DBG("%s -proxywork cancelled in calib", + __func__); + adux1050->proxy_cancel = TRUE; + cancel_delayed_work(&adux1050->proxy_work); + } + dev_dbg(adux1050->dev, "\n\n\n%s CALIB STARTED\n\n", __func__); + slp_time = get_conv_time(adux1050, CONV_DELAY_TIME); + err = adux1050->read(adux1050->dev, CONV_TIME_CTRL_REG, + &cv_time_ctrl, DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + if (CHECK_MIN_TIME(cv_time_ctrl)) { + data = SET_MIN_TIME(cv_time_ctrl); + err = adux1050->write(adux1050->dev, CONV_TIME_CTRL_REG, + &data, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Err %d\n", err); + slp_time_flag = 1; + dev_dbg(adux1050->dev, "%s Check Min time %x\n", + __func__, data); + } + + err = adux1050->read(adux1050->dev, CTRL_REG, + &power_ctrl, DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, "I2C RD Error %d\n", err); + if (GET_PWR_MODE(power_ctrl) != PWR_FULL_POWER) { + cur_power = SET_PWR_MODE(power_ctrl, PWR_FULL_POWER); + err = adux1050->write(adux1050->dev, CTRL_REG, + &cur_power, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Err %d\n", err); + slp_time_flag = slp_time_flag | 0x2; + slp_time += get_conv_time(adux1050, CONV_TIME); + dev_dbg(adux1050->dev, "Mode change %d\n", slp_time); + } else { + cur_power = power_ctrl; + } + cin_range = GET_CIN_RANGE(cur_power); + if (adux1050->metal_id < MET_VER1) { + if (cin_range != PICO_5) { + cur_power = SET_CIN_RANGE(cur_power, PICO_5); + err = adux1050->write(adux1050->dev, CTRL_REG, + &cur_power, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, + "I2C WR Err %d\n", + err); + } + } + if (slp_time_flag) { + dev_dbg(adux1050->dev, "Calib sleep %d\n", slp_time); + msleep(slp_time); + } + err = do_dac_compensation(adux1050, cur_power, + cin_range, &s_t); + dev_dbg(adux1050->dev, "calibration return %d\n", err); + } else { + adux1050->dac_calib.cal_flags = CAL_RET_NONE; + for (lp_cnt = 0; lp_cnt < TOTAL_STG; lp_cnt++) { + adux1050->pdata->cal_fact_base[lp_cnt] = 0; + adux1050->pdata->cal_offset[lp_cnt] = 0; + adux1050->pdata->digi_offset[lp_cnt] = 0; + adux1050->pdata->stg_cfg[lp_cnt] = 0; + } + } + + if (adux1050->dac_calib.action_flag) { + /* If calibration succeed set baseline by using force calib*/ + if (adux1050->dac_calib.cal_flags == CAL_RET_SUCCESS) { + dev_dbg(adux1050->dev, "before FC in calib"); + err = adux1050_force_cal(adux1050, s_t); + if (err < 0) + dev_err(adux1050->dev, "I2C RD/WR err %d\n", + err); + } + /* Restore the prv conversion time settings */ + if (slp_time_flag & 1) { + err = adux1050->write(adux1050->dev, CONV_TIME_CTRL_REG, + &cv_time_ctrl, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Err %d\n", err); + } + /* Restore the previous power Setting */ + if (slp_time_flag & 2) { + err = adux1050->write(adux1050->dev, CTRL_REG, + &power_ctrl, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Err %d\n", err); + } + } + data = adux1050->dac_calib.enable_setting | adux1050->int_pol; + err = adux1050->write(adux1050->dev, INT_CTRL_REG, &data, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Error %d\n", err); + dev_dbg(adux1050->dev, "\n\nCALIB ENDS Status %d Time %d ms\n\n", + adux1050->dac_calib.cal_flags, + jiffies_to_msecs(jiffies - start_time)); + mutex_unlock(&adux1050->mutex); + if ((adux1050->proxy_enable) && + (adux1050->dac_calib.action_flag) && + (adux1050->dev_enable)) { + adux1050->proxy_cancel = FALSE; + schedule_delayed_work(&adux1050->proxy_work, + msecs_to_jiffies + (PROXY_TIME * adux1050->allowed_proxy_time)); + } + if (adux1050->dev_enable == ADUX1050_DISABLE) { + err = adux1050_disable(adux1050); + if (err < ZERO_VAL) + dev_err(adux1050->dev, "adux1050_disable failed %d in %s\n", + err, __func__); + } + +} + +/* + * static ssize_t store_enable(struct device *dev, + * struct device_attribute *attr, + * const char *buf, size_t count) + * This function is used to enable or to disable the device. The Sysfs attribute + * is given as "enable", writing a '0' Disables the device. + * While writing '1' , enables the device. + * @param dev The Device Id structure(linux standard argument) + * @param attr Standard Linux Device attributes to the ADUX1050. + * @param buf The buffer which contains the data. + * @param count The count of bytes to be transferred to the Device. + * \note This is evoked upon an echo/write request in /sys/../devices region. + * \note This also prints the results in the console for the user. + * @return count of data written. + */ +static ssize_t store_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + char *dev_state[2] = { "DISABLED", "ENABLED"}; + s32 err; + u16 val; + + err = kstrtou16(buf, 0, &val); + if (err < 0) { + dev_err(adux1050->dev, "%s,kstrtoint failed\n", __func__); + return err; + } + if (val > 1) { + dev_dbg(adux1050->dev, "%s Invalid- Enable:1 Disable:0\n", + __func__); + goto exit; + } + dev_dbg(adux1050->dev, "%s - prv_flag %d curr %d\n", __func__, + adux1050->dev_enable, val); + if (adux1050->dev_enable == val) { + dev_dbg(adux1050->dev, "%s - Device already in %s state\n", + __func__, dev_state[val]); + goto exit; + } + if (val == ADUX1050_ENABLE) { + adux1050->dev_enable = val; +#ifdef CONFIG_ADUX1050_POLL + err = adux1050_enable(adux1050); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, " ENABLE Err %d\n", err); + adux1050->dev_enable = ZERO_VAL; + return count; + } + wake_up_process(adux1050->polling_task); +#else + enable_irq(adux1050->irq); + enable_irq_wake(adux1050->irq); + err = adux1050_enable(adux1050); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, " ENABLE Err %d\n", err); + adux1050->dev_enable = ZERO_VAL; + return count; + } +#endif + if (adux1050->proxy_enable) { + adux1050->proxy_cancel = FALSE; + schedule_delayed_work(&adux1050->proxy_work, + msecs_to_jiffies + (PROXY_TIME * adux1050->allowed_proxy_time)); + } + dev_dbg(adux1050->dev, "ADUX1050 is enabled\n"); + } else { + adux1050->dev_enable = val; +#ifdef CONFIG_ADUX1050_POLL + +#else + disable_irq_wake(adux1050->irq); + disable_irq(adux1050->irq); +#endif + err = adux1050_disable(adux1050); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, "DISABLE Err %d\n", err); + adux1050->dev_enable = ADUX1050_ENABLE; + return count; + } + adux1050->proxy_cancel = TRUE; + cancel_delayed_work(&adux1050->proxy_work); + dev_dbg(adux1050->dev, "ADUX1050 is Disabled\n"); + } +exit: + return count; +} + +/* + * static ssize_t show_enable(struct device *dev, + struct device_attribute *attr, char *buf) + * This Function is used to show the status of the driver + * Status '1' signifies the device is ENABLED, + * while the status '0' signifies a DISABLED device. + * @param dev The Device Id structure(linux standard argument) + * @param attr standard Linux Device attributes to the ADUX1050. + * @param buf The buffer to store the data to be written. + * \note This is evoked upon an cat/read request in /sys/../devices region. + * \note This also prints the results in the console for the user. + * @return The count of data written. + */ +static ssize_t show_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", adux1050->dev_enable); +} + +#ifdef CONFIG_ADUX1050_EVAL + +/* + * static ssize_t show_dumpregs(struct device *dev, + struct device_attribute *attr, char *buf) + * This Function is used for dumping the registers value of the ADUX1050. + * @param dev The Device Id structure(linux standard argument) + * @param attr standard Linux Device attributes to the ADUX1050 + * @param buf The buffer to store the data to be written + * \note This is evoked upon an cat/read request in /sys/../devices region. + * \note This also prints the results in the console for the user. + * @return count of data written + */ +static ssize_t show_dumpregs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + u16 u16temp[MAX_ADUX1050_WR_LEN]; + u32 u32_lpcnt = 0; + u16 ret = 0; + s16 err = 0; + + mutex_lock(&adux1050->mutex); + dev_dbg(adux1050->dev, "Global control registers\n"); + err = adux1050->read(adux1050->dev, DEV_ID_REG, + u16temp, GLOBAL_REG_CNT); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C Read Error %d\n", err); + goto unlock_mut; + } + for (; u32_lpcnt < GLOBAL_REG_CNT; u32_lpcnt++) { + dev_dbg(adux1050->dev, "Reg 0X%x val 0x%x\n", + u32_lpcnt, u16temp[u32_lpcnt]); + ret += snprintf(buf + ret, PAGE_SIZE, "%4x ", + u16temp[u32_lpcnt]); + } + dev_dbg(adux1050->dev, "Stage config registers\n"); + err = adux1050->read(adux1050->dev, CONFIG_STG0_REG, + u16temp, STG_CNF_CNT); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C Read Error %d\n", err); + goto unlock_mut; + } + for (u32_lpcnt = CONFIG_STG0_REG; + u32_lpcnt <= GET_HYS_REG(STG_THREE) ; u32_lpcnt++) { + dev_dbg(adux1050->dev, "Reg 0X%x val 0x%x\n", + u32_lpcnt, u16temp[u32_lpcnt-CONFIG_STG0_REG]); + ret += snprintf(buf + ret, PAGE_SIZE, "%4x ", + u16temp[u32_lpcnt-CONFIG_STG0_REG]); + } + dev_dbg(adux1050->dev, "Result/Base/p2p registers\n"); + err = adux1050->read(adux1050->dev, INT_STATUS_REG, + u16temp, STATUS_REG_CNT); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C Read Error %d\n", err); + goto unlock_mut; + } + for (u32_lpcnt = INT_STATUS_REG; + u32_lpcnt <= PROX_STATUS_REG; u32_lpcnt++) { + dev_dbg(adux1050->dev, "Reg 0X%x val 0x%x\n", + u32_lpcnt, u16temp[u32_lpcnt-INT_STATUS_REG]); + ret += snprintf(buf + ret, PAGE_SIZE, "%4x ", + u16temp[u32_lpcnt-INT_STATUS_REG]); + } +unlock_mut: + mutex_unlock(&adux1050->mutex); + return ret; +} + + +/* + * static ssize_t adux1050_name_show(struct device *dev, + struct device_attribute *attr, char *buf) + * This is used to display the device name of the chipset. + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an cat/read request in /sys/../devices region. + * @return Returns the size of the output buffer with the on/off status + */ +static ssize_t adux1050_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", DEVICE_NAME); +} + +/* + * static ssize_t adux1050_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) + * This is used to display the vendor name of the device. + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an cat/read request in /sys/../devices region. + * @return Returns the size of the output buffer with the on/off status + */ +static ssize_t adux1050_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR_NAME); +} + +/* + * static ssize_t adux1050_raw_data_show(struct device *dev, + struct device_attribute *attr, char *buf) + * This is used to display the Raw CDC data of a stage + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an cat/read request in /sys/../devices region. + * @return Returns the size of the raw data of all the stages + */ +static ssize_t adux1050_raw_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + u16 temp_cdc = 0; + s16 ret = 0; + s16 err = 0; + + if (!adux1050->dev_enable) { + ADUX1050_DRIVER_DBG("Device is not enabled\n"); + goto data_show_err; + } + mutex_lock(&adux1050->mutex); + err = adux1050->read(adux1050->dev, + GET_RESULT_REG(adux1050->stg_raw_cdc), + &temp_cdc, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C Read Error %d\n", err); + goto unlock_mut; + } + ADUX1050_DRIVER_DBG("%s, STG_NO - %d : raw_data - %x\n", __func__, + adux1050->stg_raw_cdc, temp_cdc); + ret = snprintf(buf, PAGE_SIZE, "0x%04x ", temp_cdc); +unlock_mut: + mutex_unlock(&adux1050->mutex); +data_show_err: + return ret; +} + +/* + * adux1050_raw_data_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) + * This is used to set the stage number to display CDC raw data. + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer which contains the data. + * @param count The count of bytes to be transferred to the Device. + * \note This is evoked upon an echo/write request in /sys/../devices region. + * @return Returns the count of the raw data value of a single stage + */ +static ssize_t adux1050_raw_data_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s32 err; + u16 val; + + err = kstrtou16(buf, 0, &val); + if (err) { + dev_err(adux1050->dev, "%s, kstrtoint failed\n", __func__); + return err; + } + if (val < TOTAL_STG) + adux1050->stg_raw_cdc = val; + else + ADUX1050_DRIVER_DBG("%s, Invalid input %d\n", __func__, val); + + return count; +} + +/* + * adux1050_send_event_show(struct device *dev, + struct device_attribute *attr, char *buf) + * This is used to display the send event status of the driver. + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an cat/read request in /sys/../devices region. + * @return Returns the size of the output buffer with the send event status + */ +static ssize_t adux1050_send_event_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", adux1050->send_event); +} + +/* + * adux1050_send_event_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) + * This is used to set the send event flag in the driver + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param count The count of bytes to be transferred to the Buffer + * \note This is evoked upon an write request in the /sys/.../devices region. + * @return Returns the size of the input buffer + */ +static ssize_t adux1050_send_event_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s32 val, err; + + err = kstrtoint(buf, 0, &val); + if (err < 0) { + dev_err(adux1050->dev, "%s, kstrtoint failed\n", __func__); + return err; + } + if ((val == ADUX1050_ENABLE) || (val == ADUX1050_DISABLE)) + adux1050->send_event = (unsigned char)val; + else + ADUX1050_DRIVER_DBG("%s - Invalid input %d\n", __func__, val); + return count; +} + +/* + * This is used to show the threshold status of a stage + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an read request in the /sys/.../devices region. + * @return Returns the size of the output buffer + */ +static ssize_t adux1050_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + u16 temp_base = 0; + u16 temp_ht = 0; + u16 temp_lt = 0; + u32 htresult = 0; + s32 ltresult = 0; + s16 ret = 0; + s16 err = 0; + + if (!adux1050->dev_enable) { + ADUX1050_DRIVER_DBG("Device is not enabled\n"); + goto err; + } + mutex_lock(&adux1050->mutex); + err = adux1050->read(adux1050->dev, + GET_BASE_LINE_REG(adux1050->stg_threshold), + &temp_base, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C Read Error %d\n", err); + goto unlock_mut; + } + err = adux1050->read(adux1050->dev, + GET_HIGH_TH_REG(adux1050->stg_threshold), + &temp_ht, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C Read Error %d\n", err); + goto unlock_mut; + } + err = adux1050->read(adux1050->dev, + GET_LOW_TH_REG(adux1050->stg_threshold), + &temp_lt, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C Read Error %d\n", err); + goto unlock_mut; + } + + mutex_unlock(&adux1050->mutex); + htresult = temp_base + temp_ht; + if (htresult >= FULL_SCALE_VALUE) + htresult = FULL_SCALE_VALUE; + + ltresult = temp_base - temp_lt; + if (ltresult <= 0) + ltresult = 0; + + ADUX1050_DRIVER_DBG("%s, STG_NO - %d : BS: %x, HT - %x : LT - %x\n", + __func__, adux1050->stg_threshold, + temp_base, temp_ht, temp_lt); + ret = snprintf(buf, PAGE_SIZE, "0x%04x 0x%04x ", + htresult, ltresult); + +err: + return ret; +unlock_mut: + mutex_unlock(&adux1050->mutex); + return ret; +} + +/* + * This is used to set the stage number to show the threhold details of that + * stage + * + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param count The count of bytes to be transferred to the Buffer + * \note This is evoked upon an write request in the /sys/.../devices region. + * @return Returns the size of the input buffer + */ +static ssize_t adux1050_threshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s32 err; + u16 val; + + err = kstrtou16(buf, 0, &val); + if (err) { + dev_err(adux1050->dev, "%s, kstrtoint failed\n", __func__); + return err; + } + if (val < TOTAL_STG) + adux1050->stg_threshold = val; + else + ADUX1050_DRIVER_DBG("%s, Invalid input %d\n", __func__, val); + + return count; +} + +/* + * This is used to check the DAC offset calibration work status from the driver + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an read request in the /sys/.../devices region. + * @return Returns the size of the output buffer + */ +static ssize_t adux1050_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s32 ret = 0; + s32 stg_cnt = 0; + struct adux1050_platform_data *lpdata = adux1050->pdata; + + if (adux1050->dac_calib.cal_flags == CAL_RET_SUCCESS) { + ret = snprintf(buf + ret, PAGE_SIZE, "%1d %1d ", + adux1050->dac_calib.cal_flags, adux1050->conn_stg_cnt); + for (stg_cnt = 0; stg_cnt < adux1050->num_stages; stg_cnt++) { + if (adux1050->stg_info[stg_cnt].status == + CIN_CONNECTED) { + /*The STATUS, Stage number, Target, Offset,*/ + /* SWAP_state, Digi_offset*/ + dev_dbg(adux1050->dev, + "%1d %1d 0x%04x 0x%04x 0x%04x 0x%04x ", + adux1050->dac_calib.cal_flags, stg_cnt, + lpdata->cal_fact_base[stg_cnt], + lpdata->cal_offset[stg_cnt], + lpdata->digi_offset[stg_cnt], + lpdata->stg_cfg[stg_cnt]); + ret += + snprintf(buf + ret, PAGE_SIZE, + "%1d 0x%04x 0x%04x 0x%04x 0x%04x ", + (u16)stg_cnt, + (u16)lpdata->cal_fact_base[stg_cnt], + (u16)lpdata->cal_offset[stg_cnt], + (u16)lpdata->digi_offset[stg_cnt], + (u16)lpdata->stg_cfg[stg_cnt]); + } + } + ret--; + } else { + ret = snprintf(buf, PAGE_SIZE, "%1d\n", + (u32)adux1050->dac_calib.cal_flags); + } + return ret; +} + +/* + * This is used to call the DAC offset calibration in the driver + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param size The count of bytes to be transferred to the Buffer + * \note This is evoked upon an write request in the /sys/.../devices region. + * @return Returns the size of the input buffer + */ +static ssize_t adux1050_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s32 err; + u32 val; + + err = kstrtoint(buf, 0, &val); + + if (err < 0) { + dev_err(adux1050->dev, "%s, kstrtoint failed\n", __func__); + return err; + } + + if ((val == ADUX1050_ENABLE) || (val == ADUX1050_DISABLE)) { + if (adux1050->dev_enable != ADUX1050_ENABLE) { + mutex_lock(&adux1050->mutex); + err = adux1050_hw_init(adux1050); + mutex_unlock(&adux1050->mutex); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, "HW Init failed %d\n", + err); + return size; + } + ADUX1050_DRIVER_DBG("%s, hw_init_done\n", __func__); + } + mutex_lock(&adux1050->mutex); + adux1050->dac_calib.action_flag = (u8)val; + adux1050->dac_calib.cal_flags = CAL_RET_NONE; + ADUX1050_DRIVER_DBG("%s, Calling schedule_work\n", __func__); + mutex_unlock(&adux1050->mutex); + schedule_work(&adux1050->calib_work); + } else { + dev_err(adux1050->dev, "%s, Invalid input %d\n", + __func__, val); + } + return size; +} + +#endif + +/* + * Command parsing function for echo/cat commands from command prompt. + * This function is called when ever the User tries an echo / cat command + * to the /../sysfs/devices especially during read/write registers. + * + * @return void Returns Nothing + * @see store_reg_read + */ +static int cmd_parsing(const char *buf, u16 *addr, u16 *cnt, + u16 *data, u16 data_limit) +{ + char **bp = (char **)&buf; + u8 *token, minus, parsing_cnt = 0; + u16 val; + s32 ret; + s32 pos; + + data_limit = data_limit + 2; + while ((token = strsep(bp, SPACE_CHAR))) { + pos = 0; + minus = false; + if ((char)token[pos] == MINUS_CHAR) { + minus = true; + pos++; + } + + ret = kstrtou16(&token[pos], 0, (unsigned short *)&val); + if (ret) + return ret; + if ((parsing_cnt == 0) & (val > HIGHEST_READ_REG)) + return -ERANGE; + if (minus) + val *= MINUS_VAL; + + switch (parsing_cnt) { + case PARSE_ADDR: + *addr = val; + break; + case PARSE_CNT: + *cnt = val; + break; + default: + case PARSE_DATA: + *data = val; + data++; + break; + } + parsing_cnt++; + if (parsing_cnt > data_limit) + return parsing_cnt; + } + return parsing_cnt; +} + +#ifdef CONFIG_ADUX1050_EVAL + +/* + * Command parsing function for echo/cat commands from command prompt. + * This function is called when ever the User tries an echo / cat command + * to the /../sysfs/devices especially during proxy_time + * + * @return void Returns Nothing + * @see store_proxy_time + */ +static int cmd_parsing_for_proxy(const char *buf, u16 *addr, u16 *cnt, + u16 *data, u16 data_limit) +{ + char **bp = (char **)&buf; + u8 *token, minus, parsing_cnt = 0; + u16 val; + s32 ret; + s32 pos; + + data_limit = data_limit + 2; + while ((token = strsep(bp, SPACE_CHAR))) { + pos = 0; + minus = false; + if ((char)token[pos] == MINUS_CHAR) { + minus = true; + pos++; + } + + ret = kstrtou16(&token[pos], 0, (unsigned short *)&val); + if (ret) + return ret; + if (minus) + val *= MINUS_VAL; + + switch (parsing_cnt) { + case PARSE_ADDR: + *addr = val; + break; + case PARSE_CNT: + *cnt = val; + break; + default: + case PARSE_DATA: + *data = val; + data++; + break; + } + parsing_cnt++; + if (parsing_cnt >= data_limit) + return parsing_cnt; + } + return parsing_cnt; +} + +/* + * This is used to update the calib output to the device from the application + * space + * @return The Size of the Read data + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param size The count of bytes to be transferred to the Buffer + * \note This is evoked upon an wr request in the /sys/.../devices region. + * @return Returns the size of the data handled + */ +static ssize_t adux1050_update_calib_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s32 err; + u16 data[FILP_PARAM_CNT * TOTAL_STG]; + u16 status; + u16 cnt; + + err = cmd_parsing(buf, &status, &cnt, data, + (FILP_PARAM_CNT * TOTAL_STG)); + if (err < 0) { + dev_err(adux1050->dev, "%s,kstrtos16 failed %x\n", + __func__, err); + return err; + } + dev_err(adux1050->dev, "cmd_ret %d", err); + + mutex_lock(&adux1050->mutex); + if (status == 1) { + dev_err(adux1050->dev, "%s , Invalid option\n", __func__); + } else if ((status == CAL_RET_SUCCESS) && (cnt <= TOTAL_STG)) { + if ((cnt * FILP_PARAM_CNT + sizeof(u16)) != err) { + dev_err(adux1050->dev, "%s,insuff data(%d)\n", + __func__, err); + goto err_data_cnt; + } + err = update_calib_settings(adux1050, cnt, data, + ADUX1050_ENABLE, ZERO_VAL); + if (err < ZERO_VAL) + dev_err(adux1050->dev, + "Failed in Update_calib_settings %d\n", err); + } else {/*TODO: Case 3 for File Write*/ + dev_err(adux1050->dev, "%s, Error for data val(%d)\n", + __func__, err); + } +err_data_cnt: + mutex_unlock(&adux1050->mutex); + return size; +} + + + +/* + * This is used to show the DAC calibration routine baseline CDC value. + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an read request in the /sys/.../devices region. + *@return Returns the Size of the output buffer + */ +static ssize_t calib_target_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + struct adux1050_platform_data *pdata = adux1050->pdata; + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n", pdata->req_stg0_base, + pdata->req_stg1_base, pdata->req_stg2_base, + pdata->req_stg3_base); +} + +/* + * This is used to set the DAC calibration offset baseline CDC value. + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param size The count of bytes to be transferred to the Buffer + * \note This is evoked upon an write request in the /sys/.../devices region. + * @return Returns the size of the data handled + */ +static ssize_t calib_target_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + u16 stg_num = 0; + u16 val = 0; + s32 err = 0; + u16 dummy; + + err = cmd_parsing(buf, &stg_num, &val, &dummy, 0); + if (err < 0) { + dev_err(adux1050->dev, "%s, kstrtos16 failed\n", __func__); + return err; + } + if ((val <= MAX_CALIB_TARGET) && (val >= MIN_CALIB_TARGET)) { + switch (stg_num) { + case STG_ZERO: + adux1050->pdata->req_stg0_base = val; + break; + case STG_ONE: + adux1050->pdata->req_stg1_base = val; + break; + case STG_TWO: + adux1050->pdata->req_stg2_base = val; + break; + case STG_THREE: + adux1050->pdata->req_stg3_base = val; + break; + default: + dev_dbg(adux1050->dev, "%s,Invalid stg no %d\n", + __func__, stg_num); + } + } else { + dev_err(adux1050->dev, "[%d,%d] Limit exceeded(%d)\n", + MAX_CALIB_TARGET, MIN_CALIB_TARGET, val); + } + + return size; +} + + +/* + * This is used to get register address whose data is to be read and + * count of data to be read via sysfs + * This function Reads the value at the Device's Register for the i2c client + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param count The count of bytes to be transferred to the Buffer + * \note This called when the user requires to read the configuration + * \note This is evoked upon an echo request in the /sys/.../devices region. + * \note it hold the register address to be read. + * @return The Size of the Read Register 0 if not read + * @see cmd_parsing + */ +static ssize_t store_reg_read(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + s32 ret; + u16 addr; + u16 cnt = 0; + u16 val = 0; + u16 lp_cnt = 0; + s16 err = 0; + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + + mutex_lock(&adux1050->mutex); + adux1050->stored_data_cnt = 0; + ret = cmd_parsing(buf, &addr, &cnt, &val, 0); + if (cnt == 0) { + dev_err(adux1050->dev, "[ADUX1050]: Invalid COM/ARG\n"); + goto error; + } else if (ret == -ERANGE || (addr+cnt > HIGHEST_READ_REG+1)) { + dev_err(adux1050->dev, "[ADUX1050]: Values not in RANGE\n"); + goto error; + } else if ((ret == -EINVAL) || (cnt > MAX_ADUX1050_WR_LEN)) { + dev_err(adux1050->dev, "[ADUX1050]: Invalid COMD/ARG\n"); + goto error; + } else { + val = 0; + } + memset(adux1050->stored_reg_data, 0, sizeof(adux1050->stored_reg_data)); + + err = adux1050->read(adux1050->dev, addr, + adux1050->stored_reg_data, cnt); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + goto error; + } + adux1050->stored_data_cnt = cnt; + for (lp_cnt = 0; lp_cnt < adux1050->stored_data_cnt; lp_cnt++) { + ADUX1050_AWFUL_LOG("Reg Read cmd:reg 0x%04x Data 0x%04x\n", + addr + lp_cnt, + adux1050->stored_reg_data[lp_cnt]); + } + +error: + mutex_unlock(&adux1050->mutex); + return count; +} + +/* + * This is used to read the data of the register address via sysfs sent to + * reg_read + * This function Reads the value at the Device's Register for the given + * client and Prints it in the output window + * @param dev The Device ID structure(linux standard argument) + * @param attr standard linux device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an cat request in the /sys/.../devices region. + * @return The Size of the read data, 0 if not read + * + * @see dev_get_drvdata + * @see store_reg_read + */ +static ssize_t show_reg_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s32 val = 0, lp_cnt = 0; + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + + for (lp_cnt = 0; lp_cnt < adux1050->stored_data_cnt; lp_cnt++) { + val += snprintf(buf + val, PAGE_SIZE, "0x%x ", + adux1050->stored_reg_data[lp_cnt]); + } + return val; +} + +/* + * This is used to write data to a register through i2c. + * This functions Writes the value of the buffer to the given client + * provided the count value to write + * @param dev The device ID structure(linux standard argument) + * @param attr standard linux device attributes to the ADUX1050 + * @param count The number of bytes to write from the buffer + * @param buf The buffer to store the Read data + * \note This is used to store the register address to write the data. + * \note This is evoked upon an echo request in the /sys/.../devices region. + * \note This also prints the command received before writing the Registers. + * @return The Size of the writen Data, 0 if not writen + */ +static ssize_t store_reg_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + u16 addr, cnt; + u16 wr_data[MAX_ADUX1050_WR_LEN], loop_cnt; + s32 ret; + s32 err = 0; + + mutex_lock(&adux1050->mutex); + ret = cmd_parsing(buf, &addr, &cnt, &wr_data[0], MAX_ADUX1050_WR_LEN); + if (ret == -ERANGE || (ret == -EINVAL)) { + dev_err(adux1050->dev, "%s - Values not in RANGE\n", __func__); + goto error; + } else if ((addr >= BASELINE_STG0_REG && + addr <= GET_BASE_LINE_REG(STG_THREE)) && + (addr+cnt <= GET_BASE_LINE_REG(STG_THREE) + 1)) { + ADUX1050_DRIVER_DBG("%s Baseline write register\n", __func__); + + } else if (((addr + cnt) > (HIGHEST_WR_ACCESS + 1)) || + (addr == ZERO_VAL)) { + dev_err(adux1050->dev, "%s - Addr reaches RD only regs\n", + __func__); + goto error; + } else if (cnt > MAX_ADUX1050_WR_LEN) { + dev_err(adux1050->dev, "%s - Max write length\n", __func__); + goto error; + } + ADUX1050_DRIVER_DBG("Register Write command :reg= 0x%x, size= %d\n", + addr, cnt); + + for (loop_cnt = 0; loop_cnt < cnt; loop_cnt++) { + + /* Conditions to be checked */ + /* 1.SW RESET, FORCE CALIB, AUTO_Threshold, power state ... */ + if ((addr + loop_cnt) == CTRL_REG) { + /* Clearing SW Reset bit */ + if (CHK_SW_RESET_EN(wr_data[loop_cnt])) { + ADUX1050_DRIVER_DBG("S/W reset not allowed"); + ADUX1050_DRIVER_DBG("- Use reset sysfs!!!\n"); + wr_data[loop_cnt] = + CLR_SW_RESET_EN(wr_data[loop_cnt]); + } + /*Device is not allowed to wakeup */ + /* during drv disable state*/ + if (adux1050->dev_enable == ADUX1050_DISABLE) { + if (GET_PWR_MODE(wr_data[loop_cnt]) != + PWR_STAND_BY) { + /* PWR saved, used in next enable*/ + adux1050->ctrl_reg = wr_data[loop_cnt]; + adux1050->power_mode_flag = + ADUX1050_ENABLE; + wr_data[loop_cnt] = + SET_PWR_MODE(wr_data[loop_cnt], PWR_STAND_BY); + } + } + } else if (addr + loop_cnt == BASELINE_CTRL_REG) { + if (CHK_FORCE_CALIB_EN(wr_data[loop_cnt])) { + ADUX1050_DRIVER_DBG("FORCE CAL not allowed-"); + ADUX1050_DRIVER_DBG("Use force calib sysfs\n"); + wr_data[loop_cnt] = + CLR_FORCE_CALIB_EN(wr_data[loop_cnt]); + } + } + + /* Storing local of the values before writing to registers */ + if (addr+loop_cnt <= MAX_ADUX1050_WR_LEN+1) { + adux1050->reg[addr+loop_cnt].wr_flag = ADUX1050_ENABLE; + adux1050->reg[addr+loop_cnt].value = wr_data[loop_cnt]; + } else if ((addr >= BASELINE_STG0_REG && + addr <= GET_BASE_LINE_REG(STG_THREE)) && + (addr+cnt <= GET_BASE_LINE_REG(STG_THREE) + 1)) { + if (!CHK_AUTO_TH_ENABLED( + adux1050->reg[BASELINE_CTRL_REG].value)) { + adux1050->bs_reg + [addr-BASELINE_STG0_REG + loop_cnt].wr_flag + = ADUX1050_ENABLE; + adux1050->bs_reg + [addr-BASELINE_STG0_REG + loop_cnt].value + = wr_data[loop_cnt]; + } + } + ADUX1050_DRIVER_DBG("DATA = 0x%04X\n", wr_data[loop_cnt]); + } + err = adux1050->write(adux1050->dev, addr, wr_data, cnt); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Err %d\n", err); +error: + mutex_unlock(&adux1050->mutex); + return count; +} + +/* + * This is used to update the stage details upon every change in configuration + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param count The count of bytes to be transferred to the Buffer + * \note This is evoked upon an write request in the /sys/.../devices region. + * @return Returns the size of the data handled + */ +static ssize_t store_update_config(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s32 err; + u16 val; + + if (!adux1050->dev_enable) { + ADUX1050_DRIVER_DBG("Device is not enabled\n"); + return count; + } + err = kstrtou16(buf, 0, &val); + if (err < 0) { + dev_err(adux1050->dev, "%s, kstrtos16 failed\n", __func__); + return err; + } + if (val == 1) { + mutex_lock(&adux1050->mutex); + err = get_intr_mask_info(adux1050); + err = getstageinfo(adux1050); + if (err < ZERO_VAL) + dev_err(adux1050->dev, + "Err in getstageinfo %d\n", err); + mutex_unlock(&adux1050->mutex); + msleep(adux1050->slp_time_conv_complete); + adux1050->slp_time_conv_complete = + get_conv_time(adux1050, TWICE_CONV_DELAY_TIME); + } else { + ADUX1050_DRIVER_DBG("Invalid Input %d\n", val); + } + + return count; +} + +/* + * This is used to do Software reset of the device of ADUX1050 + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param count The count of bytes to be transferred to the Buffer + * \note This is evoked upon an write request in the /sys/.../devices region. + * @return Returns the size of the data handled + */ +static ssize_t store_sw_reset(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + u16 ctrl_reg_val; + s32 err; + u16 val; + + err = kstrtou16(buf, 0, &val); + if (err < 0) { + dev_err(adux1050->dev, "%s - kstrtos16 failed\n", __func__); + return err; + } + if (val == 1) { + mutex_lock(&adux1050->mutex); + /* SW reset is enabled in ctrl register */ + err = adux1050->read(adux1050->dev, CTRL_REG, + &ctrl_reg_val, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + goto error; + } + ctrl_reg_val = SET_SW_RESET_EN(ctrl_reg_val); + err = adux1050->write(adux1050->dev, CTRL_REG, + &ctrl_reg_val, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C WR Err %d\n", err); + goto error; + } + msleep(FORCE_CALIB_SLEEP_TIME); + /*Device is put to disable mode */ + if (adux1050->dev_enable == ADUX1050_ENABLE) { + adux1050->dev_enable = ADUX1050_DISABLE; + adux1050->proxy_cancel = TRUE; + cancel_delayed_work(&adux1050->proxy_work); +#ifndef CONFIG_ADUX1050_POLL + disable_irq_wake(adux1050->irq); + disable_irq(adux1050->irq); +#endif + } +error: + mutex_unlock(&adux1050->mutex); + } else { + ADUX1050_DRIVER_DBG("%s - Invalid input %d\n", __func__, val); + } + return count; +} + +/* + * This is used to do factory calibration of the ADUX1050 + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param count The count of bytes to be transferred to the Buffer + * \note This is evoked upon an write request in the /sys/.../devices region. + * @return Returns the size of the data handled + */ +static ssize_t store_force_calib(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + u16 baseline_ctrl_val; + s32 err; + u16 val; + + err = kstrtou16(buf, 0, &val); + if (err < 0) { + dev_err(adux1050->dev, "%s, kstrtos16 failed\n", __func__); + return err; + } + if (val == 1) { + /* Force Calibration is enabled in Baseline ctrl register */ + /*TODO: Check AUTO-TH is enable or not */ + /*TODO: Can the Force calibratin be done*/ + /* when the device is at DISABLED state?*/ + mutex_lock(&adux1050->mutex); + err = adux1050->read(adux1050->dev, BASELINE_CTRL_REG, + &baseline_ctrl_val, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + goto error; + } + baseline_ctrl_val = SET_FORCE_CALIB_EN(baseline_ctrl_val); + err = adux1050->write(adux1050->dev, BASELINE_CTRL_REG, + &baseline_ctrl_val, DEF_WR); + if (err < DEF_WR) { + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + goto error; + } + msleep(FORCE_CALIB_SLEEP_TIME); +error: + mutex_unlock(&adux1050->mutex); + } else { + ADUX1050_DRIVER_DBG("%s,Value is invalid\n", __func__); + } + return count; +} + +#endif + +static ssize_t store_offset_dac_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + u16 addr, cnt; + u16 wr_data[MAX_ADUX1050_WR_LEN]; + s32 ret; + s32 err = 0; + + ret = cmd_parsing(buf, &addr, &cnt, &wr_data[0], MAX_ADUX1050_WR_LEN); + if (ret == -ERANGE || (ret == -EINVAL)) { + dev_err(adux1050->dev, "%s - Values not in RANGE\n", __func__); + return count; + } else if (cnt != 1) { + dev_err(adux1050->dev, "%s - length not 1\n", __func__); + return count; + } + switch (addr) { + case GET_OFFSET_REG(0): + case GET_OFFSET_REG(1): + break; /* right address */ + default: + dev_err(adux1050->dev, "%s - wrong address\n", __func__); + return count; + } + + ADUX1050_DRIVER_DBG("Offset Dac Write: reg= 0x%x, value= 0x%x\n", + addr, wr_data[0]); + + mutex_lock(&adux1050->mutex); + /* Storing local of the values before writing to registers */ + adux1050->reg[addr].wr_flag = ADUX1050_ENABLE; + adux1050->reg[addr].value = wr_data[0]; + ADUX1050_DRIVER_DBG("DATA = 0x%04X\n", wr_data[0]); + err = adux1050->write(adux1050->dev, addr, wr_data, cnt); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C WR Err %d\n", err); + mutex_unlock(&adux1050->mutex); + return count; +} + +#ifdef CONFIG_ADUX1050_POLL + +/* + * This is used to show the poll delay used by the driver + * @param dev The Device ID structure(linux standard argument) + * @param attr standard linux device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an cat request in the /sys/.../devices region. + * @return The Size of the read data, 0 if not read + */ +static ssize_t show_poll_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + + dev_dbg(adux1050->dev, "Poll delay =%x", adux1050->poll_delay); + return snprintf(buf, PAGE_SIZE, "%d\n", adux1050->poll_delay); +} + + + + + +/* + * This is used to set the poll delay for the adux1050 kthread which is running + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param count The count of bytes to be transferred to the Buffer + * \note This is evoked upon an write request in the /sys/.../devices region. + * @return Returns the size of the data handled + */ +static ssize_t store_poll_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s32 err; + u16 val; + + err = kstrtou16(buf, 0, &val); + if (err < 0) { + ADUX1050_DRIVER_DBG("%s -kstrou16 is not done\n", __func__); + return err; + } + if (val <= MIN_POLL_DELAY) + val = MIN_POLL_DELAY; + adux1050->poll_delay = val; + return count; +} +#endif + +#ifdef CONFIG_ADUX1050_EVAL + +/* + * This is used to read error threshold byte via sysfs to do the force + * calibration + * @param dev The Device ID structure(linux standard argument) + * @param attr standard linux device attributes to the ADUX1050 + * @param buf The buffer to store the error threshold byte + * \note This is evoked upon an cat request in the /sys/.../devices region. + * @return The Size of the read data, 0 if not read + */ +static ssize_t show_intr_err(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + + dev_dbg(adux1050->dev, "intr_err =%x", adux1050->user_intr_err); + return snprintf(buf, PAGE_SIZE, "%d\n", adux1050->user_intr_err); +} + +/* + * This is used to set the error threshold byte for the adux1050 + * @param dev The Device Id structure + * @param attr The Device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param count The count of bytes to be transferred to the Buffer + * \note This is evoked upon an write request in the /sys/.../devices region. + * @return Returns the size of the data handled + */ +static ssize_t store_intr_err(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s8 err; + u8 val; + + err = kstrtou8(buf, 0, &val); + if (err < 0) { + ADUX1050_DRIVER_DBG("%s -kstrou8 is not done\n", __func__); + return err; + } + mutex_lock(&adux1050->mutex); + adux1050->user_intr_err = val; + mutex_unlock(&adux1050->mutex); + return count; +} + +/* + * This is used to read the maximum count and work handle frequency. + * This functions Reads the value at the Device's Register for the given + * client and Prints it in the output window + * @param dev The Device ID structure(linux standard argument) + * @param attr standard linux device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an cat request in the /sys/.../Device region. + * @return The maximum count and set set time. + */ +static ssize_t show_proxy_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + + dev_dbg(adux1050->dev, + " - max_count%d\n proxy_enable bit freq: %d sec\n", + adux1050->max_proxy_count, adux1050->allowed_proxy_time); + return snprintf(buf, PAGE_SIZE, + "%d\t%d\n", + adux1050->allowed_proxy_time, + adux1050->max_proxy_count); +} + +/* + * This is used to set proxy time for force calibration + * @param dev The device ID structure(linux standard argument) + * @param attr standard linux device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * @param count The number of bytes to write from the buffer + * \note This is used to store the register address to write the data. + * \note This is evoked upon an echo request in the /sys/.../Device region. + * \note This also prints the set time and loop count. + * @return The Size of the writen Data, 0 if not writen + */ +static ssize_t store_proxy_time(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + s16 ret; + u16 val = 0; + u16 cnt = 0; + u16 data = 0; + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + + mutex_lock(&adux1050->mutex); + ret = cmd_parsing_for_proxy(buf, &val, &cnt, &data, 2); + if (cnt == 0) { + dev_err(adux1050->dev, "[ADUX1050]: Invalid cnt COM/ARG\n"); + goto error; + } else if (val == 0) { + dev_err(adux1050->dev, "[ADUX1050]: Invalid COM/ARG\n"); + goto error; + } else if (ret == -ERANGE) { + dev_err(adux1050->dev, "[ADUX1050]: Values not in RANGE\n"); + goto error; + } else if ((ret == -EINVAL)) { + dev_err(adux1050->dev, "[ADUX1050]: Invalid COMD/ARG\n"); + goto error; + } else { + data = 0; + } + adux1050->proxy_count = 0; + adux1050->allowed_proxy_time = val; + adux1050->max_proxy_count = cnt; + if ((adux1050->proxy_enable) && (adux1050->dev_enable)) { + adux1050->proxy_cancel = TRUE; + cancel_delayed_work(&adux1050->proxy_work); + ADUX1050_DRIVER_DBG("%s -proxy_time is set\n", __func__); + adux1050->proxy_cancel = FALSE; + schedule_delayed_work(&adux1050->proxy_work, + msecs_to_jiffies + (PROXY_TIME * adux1050->allowed_proxy_time)); + } + dev_dbg(adux1050->dev, "val:%d\tcnt:%d\tset time =%usec\n", + adux1050->allowed_proxy_time, + adux1050->max_proxy_count, + adux1050->max_proxy_count * adux1050->allowed_proxy_time); +error: + mutex_unlock(&adux1050->mutex); + return count; +} + +/* + * This is used to read the set time and remaining time to do force calibration. + * This functions Reads the value at the Device's Register for the given + * client and Prints it in the output window + * @param dev The Device ID structure(linux standard argument) + * @param attr standard linux device attributes to the ADUX1050 + * @param buf The buffer to store the Read data + * \note This is evoked upon an cat request in the /sys/.../Device region. + * @return The remaining time and total time. + */ +static ssize_t show_proxy_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + u32 time; + u32 rem_time; + + time = (adux1050->proxy_count * adux1050->allowed_proxy_time); + dev_dbg(adux1050->dev, "time elapsed =%dsec\n", time); + rem_time = adux1050->allowed_proxy_time * adux1050->max_proxy_count - + time; + dev_dbg(adux1050->dev, "proxy :%d\ttime left:%u sec\nset time:%u\n", + adux1050->proxy_enable, rem_time, adux1050->max_proxy_count * + adux1050->allowed_proxy_time); + return snprintf(buf, PAGE_SIZE, "%d\t%u\t%u\n", adux1050->proxy_enable, + rem_time, adux1050->max_proxy_count * + adux1050->allowed_proxy_time); +} + +/* + * This is used to enable the work function to moniter proxy time for force + * calib + * if the proximity time is not set it will set it to default values + * @param dev The device ID structure(linux standard argument) + * @param attr standard linux device attributes to the ADUX1050 + * @param buf The buffer to store the read data + * @param count The number of bytes to write from the buffer + * \note This is used to store the register address to write the data. + * \note This is evoked upon an echo request in the /sys/.../Device region. + * \note This also prints proxy enable/disable. + * @return The Size of the writen Data, 0 if not writen + */ +static ssize_t store_proxy_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct adux1050_chip *adux1050 = dev_get_drvdata(dev); + s8 err; + u8 val; + + err = kstrtou8(buf, 0, &val); + if (err < 0) { + ADUX1050_DRIVER_DBG("%s - kstrou8 is not done\n", __func__); + return err; + } + if (val > 1) { + dev_dbg(adux1050->dev, "%s :Invalid- Enable:1 Disable:0\n", + __func__); + } else if ((adux1050->proxy_enable == 1) && (val == 1)) { + dev_dbg(adux1050->dev, "%s : proximity is already enabled\n", + __func__); + goto error; + } else { + adux1050->proxy_count = 0; + adux1050->proxy_enable = val; + if ((adux1050->proxy_enable) && (adux1050->dev_enable)) { + adux1050->proxy_cancel = TRUE; + cancel_delayed_work(&adux1050->proxy_work); + ADUX1050_DRIVER_DBG("%s -proxy_correc_bit enabled\n", + __func__); + adux1050->proxy_cancel = FALSE; + schedule_delayed_work(&adux1050->proxy_work, + msecs_to_jiffies + (PROXY_TIME * adux1050->allowed_proxy_time)); + } else { + adux1050->proxy_cancel = TRUE; + cancel_delayed_work(&adux1050->proxy_work); + adux1050->proxy_count = 0; + ADUX1050_DRIVER_DBG("%s -proxy_bit/device is disable\n", + __func__); + } + } +error: + return count; +} +#endif + +/* + * The sysfs attributes used in the driver follows + */ +/*--------------------------------------------------------------*/ +static DEVICE_ATTR(adux1050_enable, S_IRUGO|S_IWUSR|S_IWGRP, + show_enable, store_enable); +/*--------------------------------------------------------------*/ +#ifdef CONFIG_ADUX1050_EVAL +static struct device_attribute dev_attr_sensor_name = + __ATTR(adux1050_device_name, S_IRUGO, + adux1050_name_show, NULL); +static struct device_attribute dev_attr_sensor_vendor = + __ATTR(adux1050_vendor, S_IRUGO, + adux1050_vendor_show, NULL); +static struct device_attribute dev_attr_sensor_raw_data = + __ATTR(adux1050_raw_data, S_IWUSR|S_IWGRP|S_IRUGO, + adux1050_raw_data_show, adux1050_raw_data_store); +static struct device_attribute dev_attr_sensor_send_event = + __ATTR(adux1050_send_event, S_IWUSR|S_IRUGO|S_IWGRP, + adux1050_send_event_show, adux1050_send_event_store); +static struct device_attribute dev_attr_sensor_threshold = + __ATTR(adux1050_threshold, S_IWUSR|S_IRUGO|S_IWGRP, + adux1050_threshold_show, adux1050_threshold_store); +static struct device_attribute dev_attr_sensor_calibration = + __ATTR(adux1050_calibration, S_IWUSR | S_IWGRP | S_IRUGO, + adux1050_calibration_show, adux1050_calibration_store); +static struct device_attribute dev_attr_sensor_update_calib = + __ATTR(adux1050_update_calib, S_IWUSR | S_IWGRP, + NULL, adux1050_update_calib_store); +static struct device_attribute dev_attr_sensor_dump = + __ATTR(adux1050_status, S_IRUGO, + show_dumpregs, NULL); +static struct device_attribute dev_attr_sensor_calib_target = + __ATTR(adux1050_calib_target, S_IRUGO | S_IWUSR | S_IWGRP, + calib_target_show, calib_target_store); +static struct device_attribute dev_attr_sensor_reg_read = + __ATTR(adux1050_reg_read, S_IWUSR | S_IWGRP | S_IRUGO, + show_reg_read, store_reg_read); +static struct device_attribute dev_attr_sensor_reg_write = + __ATTR(adux1050_reg_write, S_IWUSR | S_IWGRP, + NULL, store_reg_write); +static struct device_attribute dev_attr_sensor_update_config = + __ATTR(adux1050_update_config, S_IWUSR | S_IWGRP, + NULL, store_update_config); +static struct device_attribute dev_attr_sensor_sw_reset = + __ATTR(adux1050_sw_reset, S_IWUSR | S_IWGRP, + NULL, store_sw_reset); +static struct device_attribute dev_attr_sensor_force_calib = + __ATTR(adux1050_force_calib, S_IWUSR | S_IWGRP, + NULL, store_force_calib); +#endif +static struct device_attribute dev_attr_sensor_offset_dac_write = + __ATTR(adux1050_offset_dac_write, S_IWUSR | S_IWGRP, + NULL, store_offset_dac_write); +#ifdef CONFIG_ADUX1050_POLL +static struct device_attribute dev_attr_sensor_poll = + __ATTR(adux1050_poll_delay, S_IWUSR | S_IWGRP | S_IRUGO, + show_poll_delay, store_poll_delay); +#endif +#ifdef CONFIG_ADUX1050_EVAL +static struct device_attribute dev_attr_sensor_fc_intr_err = + __ATTR(adux1050_intr_error, S_IWUSR | S_IWGRP | S_IRUGO, + show_intr_err, store_intr_err); +static struct device_attribute dev_attr_sensor_proxy_timer_enable = + __ATTR(adux1050_proxy_enable, S_IWUSR | S_IWGRP | S_IRUGO, + show_proxy_enable, store_proxy_enable); +static struct device_attribute dev_attr_sensor_set_proxy_time = + __ATTR(adux1050_proxy_time, S_IWUSR | S_IWGRP | S_IRUGO, + show_proxy_time, store_proxy_time); +#endif +static struct attribute *adux1050_attrs[] = { + &dev_attr_adux1050_enable.attr, +#ifdef CONFIG_ADUX1050_EVAL + &dev_attr_sensor_name.attr, + &dev_attr_sensor_vendor.attr, + &dev_attr_sensor_raw_data.attr, + &dev_attr_sensor_send_event.attr, + &dev_attr_sensor_threshold.attr, + &dev_attr_sensor_calibration.attr, + &dev_attr_sensor_update_calib.attr, + &dev_attr_sensor_dump.attr, + &dev_attr_sensor_calib_target.attr, + &dev_attr_sensor_reg_read.attr, + &dev_attr_sensor_reg_write.attr, + &dev_attr_sensor_update_config.attr, + &dev_attr_sensor_sw_reset.attr, + &dev_attr_sensor_force_calib.attr, +#endif + &dev_attr_sensor_offset_dac_write.attr, +#ifdef CONFIG_ADUX1050_POLL + &dev_attr_sensor_poll.attr, +#endif +#ifdef CONFIG_ADUX1050_EVAL + &dev_attr_sensor_fc_intr_err.attr, + &dev_attr_sensor_proxy_timer_enable.attr, + &dev_attr_sensor_set_proxy_time.attr, +#endif + NULL, +}; + +static struct attribute_group adux1050_attr_group = { + .name = NULL, + .attrs = adux1050_attrs, +}; + +/* + * This routine reads the Device ID to confirm the existence + * of the Device in the System. + * @param adux1050 The Device structure + * @return 0 on successful detection of the device,-ENODEV on err. + */ +static int adux1050_hw_detect(struct adux1050_chip *adux1050) +{ + u16 data; + s16 err = 0; + + err = adux1050->read(adux1050->dev, DEV_ID_REG, &data, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + return -ENODEV; + } + if (likely((data & ADUX1050_ID_MASK) == ADUX1050_GENERIC_ID)) { + adux1050->product = PRODUCT_ID(data); + adux1050->version = REV_ID(data); + adux1050->metal_id = METAL_ID(data); + if (adux1050->metal_id < MET_VER1) + dev_dbg(adux1050->dev, + "Hopping Search Saturation Routine enabled"); + else if (adux1050->metal_id >= MET_VER1) + dev_dbg(adux1050->dev, + "Binary Search Saturation Routine enabled"); + dev_dbg(adux1050->dev, "Found ADUX1050, rev:%x met_id:%x", + adux1050->version, adux1050->metal_id); + return 0; + } + dev_err(adux1050->dev, "ADUX1050 Not Found,ID %4x\n", data); + return -ENODEV; +} + +#ifndef CONFIG_ADUX1050_POLL +/* + * Threaded IRQ Handler -- Assigns interrupt handling to work + * @param irq The Interrupt Request queue to be assigned for the device + * @param handle The data of the ADUX1050 Device + * @return IRQ_HANDLED + */ +static irqreturn_t adux1050_isr_thread(int irq, void *handle) +{ + s16 err = 0; + struct adux1050_chip *adux1050 = handle; + + if (!work_pending(&adux1050->work)) { + schedule_work(&adux1050->work); + } else { + mutex_lock(&adux1050->mutex); + /*Cleared the interrupt for future intterupts to occur*/ + err = adux1050->read(adux1050->dev, INT_STATUS_REG, + &adux1050->int_status, DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, "I2C Read Error %d in %s", + err, __func__); + + mutex_unlock(&adux1050->mutex); + } + return IRQ_HANDLED; +} +#endif + +/* + * conv_complete_cdc_fetch - Fetch the CDC for the connected stage after + * receiving the conversion sequence complete interrupt is asserted + * @param adux1050 The chip structure of ADUX1050 chip + * @return void + */ +static inline void conv_complete_cdc_fetch(struct adux1050_chip *adux1050, + u16 proxy_status) +{ + u8 stg_cnt = 0; + u16 result_cdc; + u16 baseline_cdc; + s16 err = 0; + unsigned int event_value = 0; + + for (stg_cnt = 0; stg_cnt < adux1050->num_stages; stg_cnt++) { + /** Fetch the CDC only if that stage is connected */ + if (adux1050->stg_info[stg_cnt].status != CIN_CONNECTED) + continue; + err = adux1050->read(adux1050->dev, GET_RESULT_REG(stg_cnt), + &result_cdc, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C Read Error %d in %s", + err, __func__); + err = adux1050->read(adux1050->dev, GET_BASE_LINE_REG(stg_cnt), + &baseline_cdc, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C Read Error %d in %s", + err, __func__); + if (!adux1050->send_event) + continue; + event_value = PACK_FOR_CDC_EVENT(result_cdc, stg_cnt); + input_event(adux1050->input, EV_MSC, MSC_RAW, event_value); + event_value = PACK_FOR_BASELINE_EVENT(baseline_cdc, stg_cnt); + input_event(adux1050->input, EV_MSC, MSC_RAW, event_value); + } + event_value = PACK_FOR_STATUS_EVENT(adux1050->int_status, proxy_status); + input_event(adux1050->input, EV_MSC, MSC_RAW, event_value); + input_sync(adux1050->input); +} + +/* + * This function is used to send ACTIVE event for a stage in ADUX1050 + * @param adux1050 The ADUX1050 chip structure pointer + * @param stg_num The stage nmmber for which the event to be sent + * @param threshold_type Indicates Low or High threshold + * @return void + */ +static inline void indicate_active_state(struct adux1050_chip *adux1050, + int stg_num, int threshold_type) +{ + unsigned int event_value = 0; + + ADUX1050_DRIVER_DBG("%s\n", __func__); + event_value = PACK_FOR_ACTIVE_STATE(stg_num, threshold_type); + input_event(adux1050->input, EV_MSC, MSC_RAW, event_value); + input_sync(adux1050->input); + +} + +/* + * This function is used to send IDLE event for a stage in ADUX1050 + * @param adux1050 The ADUX1050 chip structure pointer + * @param stg_num The stage nmmber for which the event to be sent + * @param threshold_type Indicates Low or High threshold + * @return void + */ +static inline void indicate_idle_state(struct adux1050_chip *adux1050, + int stg_num, int threshold_type) +{ + unsigned int event_value = 0; + + ADUX1050_DRIVER_DBG("%s\n", __func__); + event_value = PACK_FOR_IDLE_STATE(stg_num, threshold_type); + input_event(adux1050->input, EV_MSC, MSC_RAW, event_value); + input_sync(adux1050->input); +} + +/* + * high_threshold_int_check - Identify which stage asserts the high threshold + * interrupt.After identifying the stage, the state(ACTIVE,IDLE) of the stage + * is sent as input event + * @param adux1050 The chip structure of ADUX1050 chip + * @param high_status_change Contains stage number which asserts INT. + * @return void + */ +static inline void high_threshold_int_check(struct adux1050_chip *adux1050, + u16 high_status_change) +{ + u8 stg_cnt; + u8 temp_ht_enable = adux1050->high_thresh_enable; + u8 temp_ht_intr_err = GET_HIGH_STATUS(adux1050->user_intr_err); + + for (stg_cnt = 0; stg_cnt < TOTAL_STG; stg_cnt++) { + if ((!(temp_ht_intr_err & 1)) && (temp_ht_enable & 1)) { + if (high_status_change & 1) { + if (adux1050->high_status & 1) { + dev_dbg(adux1050->dev, "St = %de\n", + stg_cnt); + if (adux1050->send_event) + indicate_active_state(adux1050, + stg_cnt, + TH_HIGH); + } else { + dev_dbg(adux1050->dev, "St = %dx\n", + stg_cnt); + if (adux1050->send_event) + indicate_idle_state(adux1050, + stg_cnt, + TH_HIGH); + } + } + } + temp_ht_enable = temp_ht_enable >> 1; + high_status_change = high_status_change >> 1; + adux1050->high_status = adux1050->high_status >> 1; + temp_ht_intr_err = temp_ht_intr_err >> 1; + } +} + +/* + * Low_threshold_int_check - Identify which stage asserts the low threshold + * interrupt.After identifying the stage, the state(ACTIVE,IDLE) of the stage + * is sent as input event + * @param adux1050 The chip structure of ADUX1050 chip + * @param low_status_change Contains stage number which asserts INT. + * @return void + */ +static inline void low_threshold_int_check(struct adux1050_chip *adux1050, + u16 low_status_change) +{ + u8 stg_cnt; + u8 temp_lt_enable = adux1050->low_thresh_enable; + u8 temp_intr_err = GET_LOW_STATUS(adux1050->user_intr_err); + + for (stg_cnt = 0; stg_cnt < TOTAL_STG; stg_cnt++) { + if ((!(temp_intr_err & 1)) && (temp_lt_enable & 1)) { + if (low_status_change & 1) { + if (adux1050->low_status & 1) { + dev_dbg(adux1050->dev, "St = %de\n", + stg_cnt); + if (adux1050->send_event) + indicate_active_state(adux1050, + stg_cnt, + TH_LOW); + } else { + dev_dbg(adux1050->dev, "St = %dx\n", + stg_cnt); + if (adux1050->send_event) + indicate_idle_state(adux1050, + stg_cnt, + TH_LOW); + } + } + } + temp_lt_enable = temp_lt_enable >> 1; + low_status_change = low_status_change >> 1; + adux1050->low_status = adux1050->low_status >> 1; + temp_intr_err = temp_intr_err >> 1; + } +} +/* + * int adux1050_get_result_info(struct adux1050_chip *adux1050) + * This function is used to get the CDC,base line, high threshold and + * low threshold for the connected stages and prints the information. + * @param adux1050 The chip structure of ADUX1050 driver + * @return 0 on success. + */ +static int adux1050_get_result_info(struct adux1050_chip *adux1050) +{ + u16 rs_reg[TOTAL_STG]; + u16 ls_reg[TOTAL_STG]; + u16 hs_reg[TOTAL_STG]; + u16 base_reg[TOTAL_STG]; + u8 stg_cnt = 0; + s16 err = 0; + + for (stg_cnt = 0 ; stg_cnt < TOTAL_STG ; stg_cnt++) { + if (adux1050->stg_info[stg_cnt].status == CIN_CONNECTED) { + err = adux1050->read(adux1050->dev, + GET_RESULT_REG(stg_cnt), + &rs_reg[stg_cnt], DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + return err; + } + err = adux1050->read(adux1050->dev, + GET_HIGH_TH_REG(stg_cnt), + &hs_reg[stg_cnt], DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + return err; + } + err = adux1050->read(adux1050->dev, + GET_LOW_TH_REG(stg_cnt), + &ls_reg[stg_cnt], DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + return err; + } + err = adux1050->read(adux1050->dev, + GET_BASE_LINE_REG(stg_cnt), + &base_reg[stg_cnt], DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d\n", err); + return err; + } + dev_dbg(adux1050->dev, + "STG %x CDC %x\t BS %x\t HS %x\t LS %x\n", + stg_cnt, + rs_reg[stg_cnt], + base_reg[stg_cnt], + base_reg[stg_cnt] + hs_reg[stg_cnt], + base_reg[stg_cnt] - ls_reg[stg_cnt]); + } + } + return 0; +} + +/* + * Work Handler -- Handles the interrupt status from ADUX1050 + * @param isr_work The work structure for the ADUX1050 chip + * @return void Nothing returned + */ +static void adux1050_isr_work_fn(struct work_struct *isr_work) +{ + struct adux1050_chip *adux1050 = NULL; + u16 high_status_change = 0; + u16 low_status_change = 0; + u8 curr_intr_status = 0; + u8 user_intr_error_not = 0; + u8 stg_cnt = 0; + u8 sat_flag = 0; + u16 rs_reg[TOTAL_STG]; + u16 proxy_stage_status = 0; + s16 err = 0; + + if (isr_work == NULL) { + pr_err("%s - isr_work is NULL\n", __func__); + goto isr_null; + } + adux1050 = container_of(isr_work, struct adux1050_chip, work); + mutex_lock(&adux1050->mutex); + err = adux1050->read(adux1050->dev, INT_STATUS_REG, + &adux1050->int_status, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", err, __FILE__); + goto fc_done; + } + dev_dbg(adux1050->dev, "status_reg : %x int_status :%x DEF_WR:%x\n", + INT_STATUS_REG, adux1050->int_status, DEF_WR); + adux1050->low_status = GET_LOW_STATUS(adux1050->int_status); + adux1050->high_status = GET_HIGH_STATUS(adux1050->int_status); + adux1050->conv_status = GET_CONV_STATUS(adux1050->int_status); + dev_dbg(adux1050->dev, "HS:%x LS:%x CCS:%x\n", adux1050->high_status, + adux1050->low_status, adux1050->conv_status); +/* conditions to handle error conditions for force calibration */ + for (stg_cnt = 0; stg_cnt < TOTAL_STG; stg_cnt++) { + if (adux1050->stg_info[stg_cnt].status == CIN_CONNECTED) { + adux1050->read(adux1050->dev, GET_RESULT_REG(stg_cnt), + &rs_reg[stg_cnt], DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", + err, __FILE__); + goto fc_done; + } + ((rs_reg[stg_cnt] < MIN_CALIB_TARGET) || + (rs_reg[stg_cnt] > MAX_CALIB_TARGET)) ? + (sat_flag += 1) : sat_flag; + } + } + curr_intr_status = (u8) (adux1050->int_status & LOW_BYTE_MASK); + err = adux1050->read(adux1050->dev, PROX_STATUS_REG, + &proxy_stage_status, DEF_WR); + if (err < I2C_WRMSG_LEN) { + dev_err(adux1050->dev, "I2C RD Err %d in %s\n", err, __FILE__); + goto fc_done; + } + proxy_stage_status &= LOW_NIBBLE_MASK; + dev_dbg(adux1050->dev, "proximity status:%x", + proxy_stage_status); + if ((adux1050->user_intr_err & curr_intr_status) && (sat_flag == 0)) { + user_intr_error_not = ~(adux1050->user_intr_err); + if (!(curr_intr_status & user_intr_error_not)) { + dev_dbg(adux1050->dev, "BEFORE FC:"); + err = adux1050_get_result_info(adux1050); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, "get result fail %d\n", + err); + goto fc_done; + } + err = adux1050_force_cal(adux1050, + get_conv_time(adux1050, CONV_TIME)); + if (err < 0) { + dev_err(adux1050->dev, "ERROR in FC %d\n", err); + goto fc_done; + } + ADUX1050_DRIVER_DBG("%s -FC due to ERR condition**\n", + __func__); + dev_dbg(adux1050->dev, "AFTER FC:"); + err = adux1050_get_result_info(adux1050); + if (err < ZERO_VAL) { + dev_err(adux1050->dev, + "get result fail after FC %d\n", err); + goto fc_done; + } + } + } + /* Handling High threshold interrupt */ + if (adux1050->high_thresh_enable) { + high_status_change = ((adux1050->high_status) ^ + (adux1050->prev_high_status)); + adux1050->prev_high_status = adux1050->high_status; + if (high_status_change) { + adux1050->proxy_count = 0; + dev_dbg(adux1050->dev, "H THRES CHANGE:"); + adux1050_get_result_info(adux1050); + } + high_threshold_int_check(adux1050, high_status_change); + } + + /* Handling Low threshold interrupt */ + if (adux1050->low_thresh_enable) { + low_status_change = ((adux1050->low_status) ^ + (adux1050->prev_low_status)); + adux1050->prev_low_status = adux1050->low_status; + if (low_status_change) { + adux1050->proxy_count = 0; + dev_dbg(adux1050->dev, "L THRES CHANGE:"); + adux1050_get_result_info(adux1050); + } + low_threshold_int_check(adux1050, low_status_change); + } + /* Handling Conversion complete interrupt */ + if (adux1050->conv_enable && adux1050->conv_status) + conv_complete_cdc_fetch(adux1050, proxy_stage_status); +fc_done: + mutex_unlock(&adux1050->mutex); +isr_null: + err = 0; +} +/* + * Delayed work Handler -- Handles the proximity status from ADUX1050 + * issues the force calibration when the condition meets. + * @param proxy_dwork The work structure for the ADUX1050 chip + * @return void Nothing returned + */ +static void adux1050_proxy_work(struct work_struct *proxy_dwork) +{ + s16 err = 0; + struct adux1050_chip *adux1050 = NULL; + u16 proxy_stage_status; + u16 int_status; + + if (proxy_dwork == NULL) { + pr_err("%s - _work is NULL\n", __func__); + goto proxy_null; + } + adux1050 = container_of((struct delayed_work *) + proxy_dwork, + struct adux1050_chip, + proxy_work); + mutex_lock(&adux1050->mutex); + ADUX1050_DRIVER_DBG("%s -in delayed proxy_work!!!!!!\n", __func__); + err = adux1050->read(adux1050->dev, INT_STATUS_REG, + &int_status, DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, "I2C READ FAILED %d at %s", + err, __func__); + int_status &= LOW_BYTE_MASK; + err = adux1050->read(adux1050->dev, PROX_STATUS_REG, + &proxy_stage_status, DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, "I2C READ FAILED %d at %s", + err, __func__); + proxy_stage_status &= LOW_NIBBLE_MASK; + dev_dbg(adux1050->dev, "proximity status:%x", proxy_stage_status); + if ((int_status == 0) && (proxy_stage_status > 0)) { + adux1050->proxy_count++; + dev_dbg(adux1050->dev, "proxy_count:%x", + adux1050->proxy_count); + if (adux1050->proxy_count >= adux1050->max_proxy_count) { + adux1050->proxy_count = 0; + ADUX1050_DRIVER_DBG("%s -FC due to time limit*\n", + __func__); + err = adux1050_force_cal(adux1050, + adux1050->slp_time_conv_complete); + dev_dbg(adux1050->dev, "slp_time in FC:%x", + adux1050->slp_time_conv_complete); + if (err < 0) + dev_err(adux1050->dev, + "FC I2C READ FAILED %d at %s", + err, __func__); + } + } else { + adux1050->proxy_count = 0; + } + mutex_unlock(&adux1050->mutex); + if (!adux1050->proxy_cancel) { + schedule_delayed_work(&adux1050->proxy_work, + msecs_to_jiffies(PROXY_TIME * + adux1050->allowed_proxy_time)); + } +proxy_null: + err = 0; +} +#ifdef CONFIG_ADUX1050_POLL +/* + * adux1050_polling_thread_fn -- Run function of the ADUX1050 Kthread + * @param chip_data - Hold the pointer of ADUX1050 chip structure + * @return int - Returns Zero + */ +static int adux1050_polling_thread_fn(void *chip_data) +{ + s16 err = 0; + struct adux1050_chip *adux1050 = chip_data; + + ADUX1050_DRIVER_DBG("Polling Thread Started\n"); + while (!kthread_should_stop()) { + if (adux1050->dev_enable == ADUX1050_ENABLE) { + if (adux1050->dac_calib.cal_flags != CAL_RET_PENDING) { + if (!work_pending(&adux1050->work)) { + schedule_work(&adux1050->work); + } else { + mutex_lock(&adux1050->mutex); + /*Clear interrupt for future to occur*/ + err = adux1050->read(adux1050->dev, + INT_STATUS_REG, + &adux1050->int_status, + DEF_WR); + if (err < I2C_WRMSG_LEN) + dev_err(adux1050->dev, + "I2C RD FAIL %d at %s", + err, __func__); + mutex_unlock(&adux1050->mutex); + } + } + if (likely(adux1050->poll_delay <= MSLEEP_MIN_TIME)) + usleep_range(adux1050->poll_delay * MS_TO_US, + adux1050->poll_delay * MS_TO_US); + else + msleep(adux1050->poll_delay); + + } else { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + } + return 0; +} +#endif + +/* + * + */ +static bool read_value_from_device_tree(struct adux1050_chip *adux1050, + const char *id, unsigned short *read_value) +{ + s32 df_prop_length = 0; + const __be32 *param = NULL; + + param = of_get_property(adux1050->dt_device_node, id, &df_prop_length); + if (!param || (df_prop_length != sizeof(int))) + return false; + *read_value = be32_to_cpu(*param); + ADUX1050_DRIVER_DBG("%s read from DT, %s:%d\n", + __func__, id, *read_value); + return true; +} + +/* + * Device probe function all initialization routines are handled here like + * the ISR registration or the polling thead registeration,Work creation, + * Input device registration, SYSFS attributes creation etc. + * @param client the i2c structure of the adux1050 device/client. + * @param id The i2c_device_id for the supported i2c device. + * @return 0 on success,and On failure -ENOMEM, -EINVAL ,etc., will be returned + */ +static int adux1050_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + s32 ret = -EINVAL; + struct input_dev *input = NULL; + struct device *dev = NULL; + struct adux1050_chip *adux1050 = NULL; + + ADUX1050_DRIVER_DBG("%s called", __func__); + + if ((client == NULL) || (&client->dev == NULL)) { + pr_err("%s: Client/client->dev doesn't exist\n", __func__); + return ret; + } + dev = &client->dev; + +#ifndef CONFIG_ADUX1050_POLL + if (client->irq <= 0) { + pr_err("%s: IRQ not configured!\n", __func__); + return ret; + } +#endif + + adux1050 = kzalloc(sizeof(*adux1050), GFP_KERNEL); + if (!adux1050) { + /*WARNING: Possible unnecessary 'out of memory' message*/ + /*pr_err("%s: Memory alloc fail - Chip struct\n", __func__);*/ + return -ENOMEM; + } + + adux1050->stg_info = + kzalloc((sizeof(struct adux1050_stage_info) * TOTAL_STG), + GFP_KERNEL); + if (!adux1050->stg_info) { + /*WARNING: Possible unnecessary 'out of memory' message*/ + /*pr_err("%s: Memory Alloc fail - Stage info\n", __func__);*/ + return -ENOMEM; + } + + if (dev->platform_data == NULL) { + adux1050->pdata = &local_plat_data; + pr_debug("%s: Platform Data Not Found\n", __func__); + +#ifdef CONFIG_OF + if (client->dev.of_node != NULL) { + struct adux1050_platform_data *pdata = adux1050->pdata; + s32 df_prop_length = 0; + const __be32 *irqf = NULL; + unsigned short value = 0; + bool is_read = false; + + adux1050->dt_device_node = client->dev.of_node; + pr_debug("%s: DT node Found\n", __func__); + irqf = of_get_property(adux1050->dt_device_node, + "adi,adux1050_irq_flags", &df_prop_length); + if (irqf && (df_prop_length == sizeof(int))) { + adux1050->pdata->irq_flags = + be32_to_cpu(*irqf); + pr_debug("%s Usg irq_flag from DT %d\n", + __func__, adux1050->pdata->irq_flags); + } + is_read = read_value_from_device_tree(adux1050, + "adi,adux1050_irq_gpio_no", &value); + if (is_read) { + pdata->is_set_irq_gpio_no = true; + pdata->irq_gpio_no = value; + } + /*initialize the force calib variables*/ + is_read = read_value_from_device_tree(adux1050, + "adi,adux1050_proxy_enable", &value); + if (is_read) + pdata->proxy_enable = value; + is_read = read_value_from_device_tree(adux1050, + "adi,adux1050_allowed_proxy_time", &value); + if (is_read) + pdata->allowed_proxy_time = value; + is_read = read_value_from_device_tree(adux1050, + "adi,adux1050_max_proxy_count", &value); + if (is_read) + pdata->max_proxy_count = value; + is_read = read_value_from_device_tree(adux1050, + "adi,adux1050_intr_err", &value); + if (is_read) + pdata->intr_err = value; + } else { + pr_debug("%s - Usg local pltfm data\n", __func__); + } +#endif + + } else { + pr_debug("%s - Pltfm Data Found\n", __func__); + adux1050->pdata = dev->platform_data; + } + + adux1050->read = adux1050_i2c_read; + adux1050->write = adux1050_i2c_write; + adux1050->dev = dev; + mutex_init(&adux1050->mutex); + + /* check if the device is existing by reading device id of ADUX1050 */ + ret = adux1050_hw_detect(adux1050); + if (ret) + goto err_kzalloc_mem; + + i2c_set_clientdata(client, adux1050); + + INIT_WORK(&adux1050->work, adux1050_isr_work_fn); + INIT_WORK(&adux1050->calib_work, adux1050_calibration); + INIT_DELAYED_WORK(&adux1050->proxy_work, adux1050_proxy_work); + /* + * Allocate and register adux1050 input device + */ + input = input_allocate_device(); + if (!input) { + pr_err("%s: could not allocate input device\n", __func__); + ret = -ENOMEM; + goto err_kzalloc_mem; + } + + input->name = DEVICE_NAME; + set_bit(EV_MSC, input->evbit); + input_set_capability(input, EV_MSC, MSC_RAW); + + ret = input_register_device(input); + if (ret) { + pr_err("%s: could not input_register_device(input);\n", + __func__); + input_free_device(input); + goto err_kzalloc_mem; + } + adux1050->input = input; + input_set_drvdata(adux1050->input, adux1050); +#ifdef CONFIG_ADUX1050_POLL + /* Creation of Thread */ + adux1050->polling_task = kthread_create(adux1050_polling_thread_fn, + (void *)adux1050, "adux1050_kthread"); + if (ERR_PTR(-ENOMEM) == adux1050->polling_task) { + pr_err("%s : Thread Creation Failed\n", __func__); + goto err_free_irq; + } + if (adux1050->dev_enable == ADUX1050_ENABLE) { + pr_err("%s : before wake up\n", __func__); + wake_up_process(adux1050->polling_task); + pr_err("%s :after wake up\n", __func__); + } + adux1050->poll_delay = MIN_POLL_DELAY; + adux1050->int_pol = ACTIVE_LOW; +#else + adux1050->irq = client->irq; + if (!adux1050->pdata->irq_flags) + adux1050->pdata->irq_flags = IRQF_TRIGGER_FALLING; + + ADUX1050_DRIVER_DBG("%s - Before request_threaded_irq %d\n", + __func__, adux1050->irq); + ret = request_threaded_irq(adux1050->irq, NULL, adux1050_isr_thread, + IRQF_ONESHOT | adux1050->pdata->irq_flags, + DEVICE_NAME, adux1050); + + if (ret) { + pr_err("%s: irq %d Driver init Failed", __func__, + adux1050->irq); + goto err_free_irq; + } + disable_irq(adux1050->irq); + if (adux1050->pdata->irq_flags & IRQF_TRIGGER_RISING) + adux1050->int_pol = ACTIVE_HIGH; + else + adux1050->int_pol = ACTIVE_LOW; + + if (adux1050->pdata->is_set_irq_gpio_no) { + unsigned gpioNo = adux1050->pdata->irq_gpio_no; + + ADUX1050_DRIVER_DBG("%s: gpioNo %d\n", __func__, gpioNo); + ret = gpio_request(gpioNo, "aDuX1050"); + if (ret) { + pr_err("%s: gpio_request: %d\n", __func__, ret); + goto err_free_irq; + } + ret = gpio_direction_input(gpioNo); + if (ret) { + pr_err("%s: gpio_direction_input: %d\n", __func__, ret); + goto err_free_gpio; + } + } +#endif + ret = sysfs_create_group(&dev->kobj, &adux1050_attr_group); + if (ret) { + pr_err("%s: cound not register sensor sysfs\n", __func__); + goto err_sysfs_create_input; + } + + /* initialize and request sw/hw resources */ + adux1050_store_register_values(adux1050); + adux1050->dev_enable = ADUX1050_DISABLE; + adux1050->send_event = ADUX1050_ENABLE; + /*initialize the force calib variables*/ + adux1050->proxy_enable = adux1050->pdata->proxy_enable; + adux1050->allowed_proxy_time = adux1050->pdata->allowed_proxy_time; + adux1050->max_proxy_count = adux1050->pdata->max_proxy_count; + adux1050->user_intr_err = adux1050->pdata->intr_err; + adux1050->proxy_cancel = TRUE; +#ifdef CONFIG_ADUX1050_EVAL + adux1050->power_mode_flag = ADUX1050_DISABLE; +#endif + dev_dbg(adux1050->dev, "%s Completed\n", __func__); + return 0; + +err_sysfs_create_input: + sysfs_remove_group(&dev->kobj, &adux1050_attr_group); +#ifdef CONFIG_ADUX1050_POLL + kthread_stop(adux1050->polling_task); +#else + free_irq(adux1050->irq, adux1050); +#endif +err_free_gpio: + if (adux1050->pdata->is_set_irq_gpio_no) + gpio_free(adux1050->pdata->irq_gpio_no); +err_free_irq: + input_unregister_device(input); + +err_kzalloc_mem: + kfree(adux1050); + return ret; +} + +/* + * Removes the device. + * This is used to remove the device or the I2C client from the system + * @param client The client structure to be removed + * @return 0 on success + */ +static int adux1050_i2c_remove(struct i2c_client *client) +{ + struct adux1050_chip *adux1050 = i2c_get_clientdata(client); + u16 data = DISABLE_DEV_INT; + s16 err = 0; + + pr_debug("%s, Start\n", __func__); + if (adux1050 != NULL) { + adux1050->proxy_cancel = TRUE; + if (adux1050->dev_enable == ADUX1050_ENABLE) { + #ifdef CONFIG_ADUX1050_POLL + #else + disable_irq(adux1050->irq); + disable_irq_wake(adux1050->irq); + #endif + err = adux1050->write(adux1050->dev, INT_CTRL_REG, + &data, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C Write failed %d at %s\n", + err, __func__); + data = data | RESET_MASK; + /* Reset should be reviewed for nesesity */ + err = adux1050->write(adux1050->dev, CTRL_REG, + &data, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, "I2C Write failed %d at %s\n", + err, __func__); + } + sysfs_remove_group(&adux1050->dev->kobj, + &adux1050_attr_group); + #ifdef CONFIG_ADUX1050_POLL + kthread_stop(adux1050->polling_task); + #else + free_irq(adux1050->irq, adux1050); + #endif + cancel_work_sync(&adux1050->work); + cancel_work_sync(&adux1050->calib_work); + cancel_delayed_work(&adux1050->proxy_work); + adux1050->proxy_count = 0; + ADUX1050_DRIVER_DBG("%s -proxywork cancelled as i2c removed\n", + __func__); + input_unregister_device(adux1050->input); + pr_debug("device unregister completed & adux1050 device free called\n"); + kfree(adux1050->stg_info); /* BJ */ + pr_debug("free of stginfo complete & adux1050 free called\n"); + kfree(adux1050); + i2c_set_clientdata(client, NULL); + } + pr_debug("%s, END\n", __func__); + return 0; +} + +/* + * Used similar to driver remove function but used as a shutdown call back + * This is used to remove the device or the I2C client from the system + * @param client The client ID to be removed + * @return void + */ +void adux1050_shutdown(struct i2c_client *client) +{ + struct adux1050_chip *adux1050 = i2c_get_clientdata(client); + u16 data = DISABLE_DEV_INT; + s16 err = 0; + + pr_debug("%s, Start\n", __func__); + if (adux1050 != NULL) { + adux1050->proxy_cancel = TRUE; + if (adux1050->dev_enable == ADUX1050_ENABLE) { + #ifdef CONFIG_ADUX1050_POLL + #else + disable_irq(adux1050->irq); + disable_irq_wake(adux1050->irq); + #endif + err = adux1050->write(adux1050->dev, INT_CTRL_REG, + &data, DEF_WR); + if (err < DEF_WR) + dev_err(adux1050->dev, + "I2C Write failed %d at %s\n", + err, __func__); + } + sysfs_remove_group(&adux1050->dev->kobj, + &adux1050_attr_group); + #ifdef CONFIG_ADUX1050_POLL + kthread_stop(adux1050->polling_task); + #else + free_irq(adux1050->irq, adux1050); + #endif + cancel_work_sync(&adux1050->work); + cancel_work_sync(&adux1050->calib_work); + cancel_delayed_work(&adux1050->proxy_work); + adux1050->proxy_count = 0; + input_unregister_device(adux1050->input); + kfree(adux1050->stg_info); + kfree(adux1050); + i2c_set_clientdata(client, NULL); + } + pr_debug("%s, END\n", __func__); +} + +#ifdef CONFIG_ADUX1050_PM +/* + * Device suspend PM operation call back function + * @param dev Device structure for handling the power management. + * @return Zero on success + */ +static int adux1050_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adux1050_chip *adux1050 = i2c_get_clientdata(client); + s16 err = 0; + + dev_dbg(adux1050->dev, "%s,check (%d)\n", + __func__, adux1050->dev_enable); + /* To put device in STANDBY Mode */ + if (adux1050->dev_enable == ADUX1050_ENABLE) { + err = adux1050_disable(adux1050); + if (err < ZERO_VAL) + dev_err(adux1050->dev, "I2C RD/WR failed %d at %s\n", + err, __func__); + adux1050->proxy_cancel = TRUE; + cancel_delayed_work(&adux1050->proxy_work); + + adux1050->dev_enable = ADUX1050_SUSPEND; + } + return 0; +} + +/* + * Device resume PM operation call back function + * @param dev Device structure for handling the power management. + * @return Zero on success + */ +static int adux1050_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adux1050_chip *adux1050 = i2c_get_clientdata(client); + s16 err = 0; + + dev_dbg(adux1050->dev, "%s,check (%d)\n", + __func__, adux1050->dev_enable); + + if (adux1050->dev_enable == ADUX1050_SUSPEND) { + adux1050->dev_enable = ADUX1050_ENABLE; + err = adux1050_enable(adux1050); + if (err < ZERO_VAL) + dev_err(adux1050->dev, "I2C RD/WR failed %d at %s\n", + err, __func__); + if (adux1050->proxy_enable) { + adux1050->proxy_cancel = FALSE; + schedule_delayed_work(&adux1050->proxy_work, + msecs_to_jiffies + (PROXY_TIME * adux1050->allowed_proxy_time)); + } +#ifdef CONFIG_ADUX1050_POLL + wake_up_process(adux1050->polling_task); +#endif + } + + return 0; +} +#endif + +/* + * Device ID table for the ADUX1050 driver + */ +static const struct of_device_id adux1050_of_id[] = { + {.compatible = "adi,adux1050"}, + {} +}; + +/* + * Device ID table for the ADUX1050 driver + */ +static const struct i2c_device_id adux1050_id[] = { + { "adux1050", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, adux1050_id); + +#ifdef CONFIG_ADUX1050_PM +/* + * The file Operation table for power + */ +static const struct dev_pm_ops adux1050_dev_pm_ops = { + .suspend = adux1050_i2c_suspend, + .resume = adux1050_i2c_resume, +}; +#endif + +/* + * I2C driver structure containing the function callbacks, + * driver name and ID tables + */ +struct i2c_driver adux1050_i2c_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_ADUX1050_PM + .pm = &adux1050_dev_pm_ops, +#endif +#ifdef CONFIG_OF + .of_match_table = adux1050_of_id, +#endif + }, + .probe = adux1050_probe, + .shutdown = adux1050_shutdown, + .remove = adux1050_i2c_remove, + .id_table = adux1050_id, +}; + +/* + * This is an init function called during module insertion. + * calls in turn i2c driver probe function + */ +static int adux1050_module_init(void) +{ + pr_debug("%s,START\n", __func__); + return i2c_add_driver(&adux1050_i2c_driver); +} +module_init(adux1050_module_init); + +/* + * This is an exit function called during module removal -- + * calls in turn i2c driver delete function + */ +static void adux1050_module_exit(void) +{ + i2c_del_driver(&adux1050_i2c_driver); +} + +module_exit(adux1050_module_exit); +MODULE_DESCRIPTION("Analog Devices ADUX1050 Driver"); +MODULE_AUTHOR("Analog Devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/bu520x1nvx.c b/drivers/input/misc/bu520x1nvx.c new file mode 100644 index 0000000000000000000000000000000000000000..74656360782d8564d914a0744c1eb4714f07e2e5 --- /dev/null +++ b/drivers/input/misc/bu520x1nvx.c @@ -0,0 +1,635 @@ +/* drivers/input/misc/bu520x1nvx.c + * + * Author: Takashi Shiina + * Tadashi Kubo + * Shogo Tanaka + * Atsushi Iyogi + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BU520X1NVX_DEV_NAME "bu520x1nvx" +#define BU520X1NVX_SW_LID_NAME "lid" +#define BU520X1NVX_SW_KEYDOCK_NAME "keyboard_dock" +#define BU520X1NVX_SWITCH_NUM 2 + +struct bu520x1nvx_event_data { + const struct bu520x1nvx_gpio_event *event; + struct timer_list det_timer; + struct work_struct det_work; + unsigned int irq; +}; + +struct bu520x1nvx_drvdata { + struct device *dev; + struct pinctrl *key_pinctrl; + struct input_dev *input_dev; + struct switch_dev switch_lid; + struct switch_dev switch_keydock; + struct mutex lock; + atomic_t detection_in_progress; + unsigned int n_events; + struct bu520x1nvx_event_data data[0]; +}; + +enum bu520x1nvx_input_state { + LID_OPEN, + LID_CLOSE, +}; + +enum bu520x1nvx_switch_state { + SWITCH_OFF, + SWITCH_ON, +}; + +static int bu520x1nvx_get_lid_state(const struct bu520x1nvx_gpio_event *event) +{ + return (gpio_get_value_cansleep(event->gpio) + ^ event->active_low ? + LID_CLOSE : LID_OPEN); +} + +static void bu520x1nvx_report_input_event(struct input_dev *idev, + const struct bu520x1nvx_gpio_event *event) +{ + int gpio_state = bu520x1nvx_get_lid_state(event); + dev_dbg(&idev->dev, "%s: value(%d)\n", __func__, gpio_state); + input_report_switch(idev, SW_LID, gpio_state); + input_sync(idev); +} + +static void bu520x1nvx_report_switch_event(struct switch_dev *switch_dev, + const struct bu520x1nvx_gpio_event *event) +{ + int gpio_state = (gpio_get_value_cansleep(event->gpio) + ^ event->active_low ? + SWITCH_ON : SWITCH_OFF); + + dev_dbg(switch_dev->dev, "%s: value(%d)\n", __func__, gpio_state); + switch_set_state(switch_dev, gpio_state); +} + +static int bu520x1nvx_get_devtree(struct device *dev, + struct bu520x1nvx_platform_data *pdata) +{ + struct device_node *node, *pp = NULL; + int i = 0; + struct bu520x1nvx_gpio_event *events; + u32 reg; + int gpio; + int ret = -ENODEV; + + node = dev->of_node; + if (node == NULL) + goto fail; + + memset(pdata, 0, sizeof(*pdata)); + + pdata->n_events = 0; + pp = NULL; + while ((pp = of_get_next_child(node, pp))) + pdata->n_events++; + + if (pdata->n_events == 0) + goto fail; + + events = kzalloc(pdata->n_events * sizeof(*events), GFP_KERNEL); + if (!events) { + ret = -ENOMEM; + goto fail; + } + + while ((pp = of_get_next_child(node, pp))) { + enum of_gpio_flags flags; + + if (!of_find_property(pp, "gpios", NULL)) { + pdata->n_events--; + dev_warn(dev, "Found button without gpios\n"); + continue; + } + + gpio = of_get_gpio_flags(pp, 0, &flags); + if (!gpio_is_valid(gpio)) { + dev_err(dev, "%s: invalid gpio %d\n", __func__, gpio); + goto out_fail; + } + events[i].gpio = gpio; + events[i].active_low = flags & OF_GPIO_ACTIVE_LOW; + + if (!of_property_read_u32(pp, "lid-pin", ®)) + events[i].lid_pin = reg; + + events[i].desc = of_get_property(pp, "label", NULL); + + if (of_property_read_u32(pp, "debounce-interval", ®) == 0) + events[i].debounce_interval = reg; + if (of_property_read_u32(pp, "open-debounce-interval", + ®) == 0) + events[i].open_debounce_interval = reg; + if (of_property_read_u32(pp, "close-debounce-interval", + ®) == 0) + events[i].close_debounce_interval = reg; + i++; + } + pdata->events = events; + + return 0; + +out_fail: + kfree(events); +fail: + return ret; +} + +static irqreturn_t bu520x1nvx_isr(int irq, void *data) +{ + struct bu520x1nvx_event_data *edata = + (struct bu520x1nvx_event_data *)data; + const struct bu520x1nvx_gpio_event *event = edata->event; + struct bu520x1nvx_drvdata *ddata = container_of(edata, + struct bu520x1nvx_drvdata, + data[!event->lid_pin]); + + unsigned int timer_debounce; + + if (event->lid_pin) { + if (bu520x1nvx_get_lid_state(event) == LID_OPEN) + timer_debounce = event->open_debounce_interval; + else + timer_debounce = event->close_debounce_interval; + } else { + timer_debounce = event->debounce_interval; + } + + if (timer_debounce) + mod_timer(&edata->det_timer, + jiffies + msecs_to_jiffies(timer_debounce)); + else + schedule_work(&edata->det_work); + + atomic_set(&ddata->detection_in_progress, 1); + + return IRQ_HANDLED; +} + +static void bu520x1nvx_det_tmr_func(unsigned long func_data) +{ + struct bu520x1nvx_event_data *edata = + (struct bu520x1nvx_event_data *)func_data; + + schedule_work(&edata->det_work); +} + +static void bu520x1nvx_det_work(struct work_struct *work) +{ + struct bu520x1nvx_event_data *edata = + container_of(work, struct bu520x1nvx_event_data, det_work); + const struct bu520x1nvx_gpio_event *event = edata->event; + struct bu520x1nvx_drvdata *ddata = container_of(edata, + struct bu520x1nvx_drvdata, + data[!event->lid_pin]); + + if (event->lid_pin) { + bu520x1nvx_report_switch_event(&ddata->switch_lid, event); + bu520x1nvx_report_input_event(ddata->input_dev, event); + } else { + bu520x1nvx_report_switch_event(&ddata->switch_keydock, event); + } + + atomic_set(&ddata->detection_in_progress, 0); +} + +static int bu520x1nvx_pinctrl_configure(struct bu520x1nvx_drvdata *ddata, + bool active) +{ + struct pinctrl_state *set_state; + int retval; + + if (active) { + set_state = + pinctrl_lookup_state(ddata->key_pinctrl, + "tlmm_bu520x1nvx_active"); + if (IS_ERR(set_state)) { + dev_err(ddata->dev, + "cannot get ts pinctrl active state\n"); + goto lookup_err; + } + } else { + set_state = + pinctrl_lookup_state(ddata->key_pinctrl, + "tlmm_bu520x1nvx_suspend"); + if (IS_ERR(set_state)) { + dev_err(ddata->dev, + "cannot get gpiokey pinctrl sleep state\n"); + goto lookup_err; + } + } + retval = pinctrl_select_state(ddata->key_pinctrl, set_state); + if (retval) { + dev_err(ddata->dev, + "cannot set ts pinctrl active state\n"); + goto select_err; + } + + return 0; + +lookup_err: + return PTR_ERR(set_state); +select_err: + return retval; +} + +static int bu520x1nvx_open(struct input_dev *idev) +{ + struct bu520x1nvx_drvdata *ddata = input_get_drvdata(idev); + struct bu520x1nvx_event_data *edata; + const struct bu520x1nvx_gpio_event *event; + int i; + + mutex_lock(&ddata->lock); + for (i = 0; i < ddata->n_events; i++) { + edata = &ddata->data[i]; + event = edata->event; + + if (event->lid_pin) + bu520x1nvx_report_input_event(ddata->input_dev, event); + } + mutex_unlock(&ddata->lock); + + return 0; +} + +static int bu520x1nvx_setup_event(struct platform_device *pdev, + struct bu520x1nvx_event_data *edata, + const struct bu520x1nvx_gpio_event *event) +{ + const char *desc = event->desc ? event->desc : BU520X1NVX_DEV_NAME; + struct device *dev = &pdev->dev; + irq_handler_t isr; + unsigned long irqflags; + int irq, error; + + edata->event = event; + + error = gpio_request(event->gpio, desc); + if (error < 0) { + dev_err(dev, "Failed to request GPIO %d, error %d\n", + event->gpio, error); + goto request_fail; + } + + error = gpio_direction_input(event->gpio); + if (error < 0) { + dev_err(dev, + "Failed to configure direction for GPIO %d, error %d\n", + event->gpio, error); + goto fail; + } + + irq = gpio_to_irq(event->gpio); + if (irq < 0) { + error = irq; + dev_err(dev, + "Unable to get irq number for GPIO %d, error %d\n", + event->gpio, error); + goto fail; + } + edata->irq = irq; + + isr = bu520x1nvx_isr; + irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + + INIT_WORK(&edata->det_work, bu520x1nvx_det_work); + + setup_timer(&edata->det_timer, + bu520x1nvx_det_tmr_func, (unsigned long)edata); + + error = request_any_context_irq(edata->irq, isr, irqflags, desc, edata); + if (error < 0) { + dev_err(dev, "Unable to claim irq %d; error %d\n", + event->irq, error); + goto fail; + } + enable_irq_wake(edata->irq); + + return 0; + +fail: + if (gpio_is_valid(event->gpio)) + gpio_free(event->gpio); +request_fail: + return error; +} + +static void bu520x1nvx_remove_event(struct bu520x1nvx_event_data *edata) +{ + free_irq(edata->irq, edata); + del_timer_sync(&edata->det_timer); + cancel_work_sync(&edata->det_work); + if (gpio_is_valid(edata->event->gpio)) + gpio_free(edata->event->gpio); +} + +static int bu520x1nvx_set_input_device(struct bu520x1nvx_drvdata *ddata) +{ + struct input_dev *input; + int error = 0; + + input = input_allocate_device(); + if (!input) { + dev_err(ddata->dev, "failed to allocate input_dev (%s)\n", + __func__); + error = -ENOMEM; + goto out; + } + ddata->input_dev = input; + + input_set_drvdata(ddata->input_dev, ddata); + + ddata->input_dev->name = BU520X1NVX_DEV_NAME; + ddata->input_dev->open = bu520x1nvx_open; + + error = input_register_device(ddata->input_dev); + if (error) { + dev_err(ddata->dev, "failed to register device (%s)\n", + __func__); + goto fail; + } + input_set_capability(ddata->input_dev, EV_SW, SW_LID); + + goto out; + +fail: + input_unregister_device(ddata->input_dev); +out: + return error; + +} + +static int bu520x1nvx_set_switch_device(struct bu520x1nvx_drvdata *ddata, + bool lid_pin) +{ + int error = 0; + + if (lid_pin) { + ddata->switch_lid.name = BU520X1NVX_SW_LID_NAME; + ddata->switch_lid.state = SWITCH_OFF; + error = switch_dev_register(&ddata->switch_lid); + if (error) { + dev_err(ddata->dev, "%s cannot regist lid(%d)\n", + __func__, error); + goto out; + } + } else { + ddata->switch_keydock.name = BU520X1NVX_SW_KEYDOCK_NAME; + ddata->switch_keydock.state = SWITCH_OFF; + error = switch_dev_register(&ddata->switch_keydock); + if (error) { + dev_err(ddata->dev, "%s cannot regist keydock(%d)\n", + __func__, error); + goto fail_switch; + } + } + goto out; + +fail_switch: + switch_dev_unregister(&ddata->switch_lid); +out: + return error; +} + +static int bu520x1nvx_probe(struct platform_device *pdev) +{ + struct bu520x1nvx_platform_data *pdata = pdev->dev.platform_data; + struct bu520x1nvx_platform_data alt_pdata; + const struct bu520x1nvx_gpio_event *event; + struct bu520x1nvx_event_data *edata; + struct bu520x1nvx_drvdata *ddata; + struct switch_dev *switch_dev; + int i = 0; + int error = 0; + struct pinctrl_state *set_state; + + if (!pdata) { + error = bu520x1nvx_get_devtree(&pdev->dev, &alt_pdata); + if (error) + goto fail; + pdata = &alt_pdata; + } + + ddata = kzalloc(sizeof(struct bu520x1nvx_drvdata) + + pdata->n_events * sizeof(struct bu520x1nvx_event_data), + GFP_KERNEL); + if (!ddata) { + dev_err(&pdev->dev, "failed to allocate drvdata in probe\n"); + error = -ENOMEM; + goto fail; + } + + ddata->dev = &pdev->dev; + ddata->n_events = pdata->n_events; + ddata->key_pinctrl = devm_pinctrl_get(ddata->dev); + mutex_init(&ddata->lock); + + platform_set_drvdata(pdev, ddata); + + if (IS_ERR(ddata->key_pinctrl)) { + if (PTR_ERR(ddata->key_pinctrl) == -EPROBE_DEFER) + goto fail_pinctrl; + pr_debug("Target does not use pinctrl\n"); + ddata->key_pinctrl = NULL; + } + + if (ddata->key_pinctrl) { + error = bu520x1nvx_pinctrl_configure(ddata, true); + if (error) { + dev_err(ddata->dev, + "cannot set ts pinctrl active state\n"); + goto fail_pinctrl; + } + } + + for (i = 0; i < pdata->n_events; i++) { + event = &pdata->events[i]; + edata = &ddata->data[i]; + + if (event->lid_pin) { + error = bu520x1nvx_set_input_device(ddata); + if (error) { + dev_err(ddata->dev, + "%s cannot set input dev(%d)\n", + __func__, error); + goto fail_setup_event; + } + } + + error = bu520x1nvx_set_switch_device(ddata, event->lid_pin); + if (error) { + dev_err(ddata->dev, "%s cannot set switch dev(%d)\n", + __func__, error); + goto fail_setup_event; + } + + error = bu520x1nvx_setup_event(pdev, edata, event); + if (error) { + dev_err(ddata->dev, "%s cannot set event error(%d)\n", + __func__, error); + goto fail_setup_event; + } + + if (event->lid_pin) + switch_dev = &ddata->switch_lid; + else + switch_dev = &ddata->switch_keydock; + + bu520x1nvx_report_switch_event(switch_dev, event); + } + + return 0; + +fail_setup_event: + if (ddata->switch_lid.dev) + switch_dev_unregister(&ddata->switch_lid); + if (ddata->switch_keydock.dev) + switch_dev_unregister(&ddata->switch_keydock); + if (&ddata->input_dev->dev) { + input_unregister_device(ddata->input_dev); + input_free_device(ddata->input_dev); + } + if (ddata->key_pinctrl) { + set_state = + pinctrl_lookup_state(ddata->key_pinctrl, + "tlmm_bu520x1nvx_suspend"); + if (IS_ERR(set_state)) + dev_err(ddata->dev, "cannot get pinctrl sleep state\n"); + else + pinctrl_select_state(ddata->key_pinctrl, set_state); + } + while (--i >= 0) + bu520x1nvx_remove_event(&ddata->data[i]); + platform_set_drvdata(pdev, NULL); +fail_pinctrl: + mutex_destroy(&ddata->lock); + kzfree(ddata); +fail: + return error; +} + +static int bu520x1nvx_remove(struct platform_device *pdev) +{ + int i; + struct bu520x1nvx_drvdata *ddata = platform_get_drvdata(pdev); + + if (ddata->switch_lid.dev) + switch_dev_unregister(&ddata->switch_lid); + if (ddata->switch_keydock.dev) + switch_dev_unregister(&ddata->switch_keydock); + if (&ddata->input_dev->dev) + input_unregister_device(ddata->input_dev); + mutex_destroy(&ddata->lock); + for (i = 0; i < ddata->n_events; i++) + bu520x1nvx_remove_event(&ddata->data[i]); + if (!pdev->dev.platform_data) + kfree(ddata->data[0].event); + kzfree(ddata); + + return 0; +} + +static int bu520x1nvx_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct bu520x1nvx_drvdata *ddata = platform_get_drvdata(pdev); + int ret = 0; + + if (ddata->key_pinctrl) { + ret = bu520x1nvx_pinctrl_configure(ddata, false); + if (ret) { + dev_err(&pdev->dev, "failed to put the pin\n"); + goto out; + } + } + + if (atomic_read(&ddata->detection_in_progress)) { + dev_dbg(&pdev->dev, "detection in progress. (%s)\n", + __func__); + ret = -EAGAIN; + } + +out: + return ret; +} + +static int bu520x1nvx_resume(struct platform_device *pdev) +{ + struct bu520x1nvx_drvdata *ddata = platform_get_drvdata(pdev); + int ret = 0; + + if (ddata->key_pinctrl) { + ret = bu520x1nvx_pinctrl_configure(ddata, true); + if (ret) + dev_err(&pdev->dev, "failed to put the pin\n"); + } + + return ret; +} + +static struct of_device_id bu520x1nvx_match_table[] = { + { .compatible = "rohm,bu520x1nvx", + }, + {} +}; + +static struct platform_driver bu520x1nvx_driver = { + .probe = bu520x1nvx_probe, + .remove = bu520x1nvx_remove, + .suspend = bu520x1nvx_suspend, + .resume = bu520x1nvx_resume, + .driver = { + .name = BU520X1NVX_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = bu520x1nvx_match_table, + }, +}; + +static int __init bu520x1nvx_init(void) +{ + return platform_driver_register(&bu520x1nvx_driver); +} + +static void __exit bu520x1nvx_exit(void) +{ + platform_driver_unregister(&bu520x1nvx_driver); +} + +module_init(bu520x1nvx_init); +module_exit(bu520x1nvx_exit); + +MODULE_LICENSE("GPLv2"); + diff --git a/drivers/input/misc/fpc1145_platform.c b/drivers/input/misc/fpc1145_platform.c new file mode 100644 index 0000000000000000000000000000000000000000..06605160de036c10c17cba965f9039b69e6ba3e4 --- /dev/null +++ b/drivers/input/misc/fpc1145_platform.c @@ -0,0 +1,583 @@ +/* + * FPC1145 Fingerprint sensor device driver + * + * This driver will control the platform resources that the FPC fingerprint + * sensor needs to operate. The major things are probing the sensor to check + * that it is actually connected and let the Kernel know this and with that also + * enabling and disabling of regulators, sensor reset line, sensor IRQ line. + * + * The driver will expose most of its available functionality in sysfs which + * enables dynamic control of these features from eg. a user space process. + * + * The sensor's IRQ events will be pushed to Kernel's event handling system and + * are exposed in the drivers event node. + * + * Copyright (c) 2016 Fingerprint Cards AB + * + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FPC1145_RESET_LOW_US 1000 +#define FPC1145_RESET_HIGH1_US 100 +#define FPC1145_RESET_HIGH2_US 1250 +#define PWR_ON_STEP_SLEEP 100 +#define PWR_ON_STEP_RANGE1 100 +#define PWR_ON_STEP_RANGE2 900 +#define NUM_PARAMS_REG_ENABLE_SET 2 + +static const char * const pctl_names[] = { + "fpc1145_reset_reset", + "fpc1145_reset_active", + "fpc1145_irq_active", +}; + +struct vreg_config { + char *name; + unsigned long vmin; + unsigned long vmax; + int ua_load; +}; + +static const struct vreg_config const vreg_conf[] = { + { "vdd_ana", 1800000UL, 1800000UL, 6000, }, + { "vcc_spi", 1800000UL, 1800000UL, 10, }, + { "vdd_io", 1800000UL, 1800000UL, 6000, }, +}; + +struct fpc1145_data { + struct device *dev; + struct pinctrl *fingerprint_pinctrl; + struct pinctrl_state *pinctrl_state[ARRAY_SIZE(pctl_names)]; + struct regulator *vreg[ARRAY_SIZE(vreg_conf)]; + + int irq_gpio; + int rst_gpio; + struct mutex lock; + bool prepared; + bool vcc_spi; + bool vdd_io; + bool vdd_ana; +}; + +static int vreg_setup(struct fpc1145_data *fpc1145, const char *name, + bool enable) +{ + size_t i; + int rc; + struct regulator *vreg; + struct device *dev = fpc1145->dev; + + for (i = 0; i < ARRAY_SIZE(fpc1145->vreg); i++) { + const char *n = vreg_conf[i].name; + + if (!strncmp(n, name, strlen(n))) + goto found; + } + dev_err(dev, "Regulator %s not found\n", name); + return -EINVAL; +found: + vreg = fpc1145->vreg[i]; + if (enable) { + if (!vreg) { + vreg = regulator_get(dev, name); + if (IS_ERR(vreg)) { + dev_err(dev, "Unable to get %s\n", name); + return PTR_ERR(vreg); + } + } + if (regulator_count_voltages(vreg) > 0) { + rc = regulator_set_voltage(vreg, vreg_conf[i].vmin, + vreg_conf[i].vmax); + if (rc) + dev_err(dev, + "Unable to set voltage on %s, %d\n", + name, rc); + } + rc = regulator_set_load(vreg, vreg_conf[i].ua_load); + if (rc < 0) + dev_err(dev, "Unable to set current on %s, %d\n", + name, rc); + rc = regulator_enable(vreg); + if (rc) { + dev_err(dev, "error enabling %s: %d\n", name, rc); + regulator_put(vreg); + vreg = NULL; + } + fpc1145->vreg[i] = vreg; + } else { + if (vreg) { + if (regulator_is_enabled(vreg)) { + regulator_disable(vreg); + dev_dbg(dev, "disabled %s\n", name); + } + regulator_put(vreg); + fpc1145->vreg[i] = NULL; + } + rc = 0; + } + return rc; +} + +/** + * Will try to select the set of pins (GPIOS) defined in a pin control node of + * the device tree named @p name. + * + * The node can contain several eg. GPIOs that is controlled when selecting it. + * The node may activate or deactivate the pins it contains, the action is + * defined in the device tree node itself and not here. The states used + * internally is fetched at probe time. + * + * @see pctl_names + * @see fpc1145_probe + */ +static int select_pin_ctl(struct fpc1145_data *fpc1145, const char *name) +{ + size_t i; + int rc; + struct device *dev = fpc1145->dev; + + for (i = 0; i < ARRAY_SIZE(fpc1145->pinctrl_state); i++) { + const char *n = pctl_names[i]; + + if (!strncmp(n, name, strlen(n))) { + rc = pinctrl_select_state(fpc1145->fingerprint_pinctrl, + fpc1145->pinctrl_state[i]); + if (rc) + dev_err(dev, "cannot select '%s'\n", name); + else + dev_dbg(dev, "Selected '%s'\n", name); + goto exit; + } + } + rc = -EINVAL; + dev_err(dev, "%s:'%s' not found\n", __func__, name); +exit: + return rc; +} + +static ssize_t pinctl_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fpc1145_data *fpc1145 = dev_get_drvdata(dev); + int rc = select_pin_ctl(fpc1145, buf); + + return rc ? rc : count; +} +static DEVICE_ATTR(pinctl_set, S_IWUSR, NULL, pinctl_set); + +static ssize_t regulator_enable_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fpc1145_data *fpc1145 = dev_get_drvdata(dev); + char op; + char name[16]; + int rc; + bool enable; + + if (NUM_PARAMS_REG_ENABLE_SET != sscanf(buf, "%15s,%c", name, &op)) + return -EINVAL; + if (op == 'e') + enable = true; + else if (op == 'd') + enable = false; + else + return -EINVAL; + rc = vreg_setup(fpc1145, name, enable); + return rc ? rc : count; +} +static DEVICE_ATTR(regulator_enable, S_IWUSR, NULL, regulator_enable_set); + +static int hw_reset(struct fpc1145_data *fpc1145) +{ + int irq_gpio; + struct device *dev = fpc1145->dev; + int rc = select_pin_ctl(fpc1145, "fpc1145_reset_active"); + + if (rc) + goto exit; + usleep_range(FPC1145_RESET_HIGH1_US, FPC1145_RESET_HIGH1_US + 100); + + rc = select_pin_ctl(fpc1145, "fpc1145_reset_reset"); + if (rc) + goto exit; + usleep_range(FPC1145_RESET_LOW_US, FPC1145_RESET_LOW_US + 100); + + rc = select_pin_ctl(fpc1145, "fpc1145_reset_active"); + if (rc) + goto exit; + usleep_range(FPC1145_RESET_HIGH1_US, FPC1145_RESET_HIGH1_US + 100); + + irq_gpio = gpio_get_value(fpc1145->irq_gpio); + dev_info(dev, "IRQ after reset %d\n", irq_gpio); +exit: + return rc; +} + +static ssize_t hw_reset_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + struct fpc1145_data *fpc1145 = dev_get_drvdata(dev); + + if (!strncmp(buf, "reset", strlen("reset"))) + rc = hw_reset(fpc1145); + else + return -EINVAL; + return rc ? rc : count; +} +static DEVICE_ATTR(hw_reset, S_IWUSR, NULL, hw_reset_set); + +/** + * Will setup clocks, GPIOs, and regulators to correctly initialize the touch + * sensor to be ready for work. + * + * In the correct order according to the sensor spec this function will + * enable/disable regulators, SPI platform clocks, and reset line, all to set + * the sensor in a correct power on or off state "electrical" wise. + * + * @see spi_prepare_set + * @note This function will not send any commands to the sensor it will only + * control it "electrically". + */ +static int device_prepare(struct fpc1145_data *fpc1145, bool enable) +{ + int rc; + + mutex_lock(&fpc1145->lock); + if (enable && !fpc1145->prepared) { + + fpc1145->prepared = true; + select_pin_ctl(fpc1145, "fpc1145_reset_reset"); + + if (fpc1145->vcc_spi) { + rc = vreg_setup(fpc1145, "vcc_spi", true); + if (rc) + goto exit; + } + + if (fpc1145->vdd_io) { + rc = vreg_setup(fpc1145, "vdd_io", true); + if (rc) + goto exit_1; + } + + if (fpc1145->vdd_ana) { + rc = vreg_setup(fpc1145, "vdd_ana", true); + if (rc) + goto exit_2; + } + + usleep_range(PWR_ON_STEP_SLEEP, + PWR_ON_STEP_SLEEP + PWR_ON_STEP_RANGE2); + + (void)select_pin_ctl(fpc1145, "fpc1145_reset_active"); + usleep_range(PWR_ON_STEP_SLEEP, + PWR_ON_STEP_SLEEP + PWR_ON_STEP_RANGE1); + + } else if (!enable && fpc1145->prepared) { + rc = 0; + + (void)select_pin_ctl(fpc1145, "fpc1145_reset_reset"); + usleep_range(PWR_ON_STEP_SLEEP, + PWR_ON_STEP_SLEEP + PWR_ON_STEP_RANGE2); + + if (fpc1145->vdd_ana) + (void)vreg_setup(fpc1145, "vdd_ana", false); +exit_2: + if (fpc1145->vdd_io) + (void)vreg_setup(fpc1145, "vdd_io", false); +exit_1: + if (fpc1145->vcc_spi) + (void)vreg_setup(fpc1145, "vcc_spi", false); +exit: + fpc1145->prepared = false; + } else { + rc = 0; + } + mutex_unlock(&fpc1145->lock); + return rc; +} + +static ssize_t device_prepare_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + struct fpc1145_data *fpc1145 = dev_get_drvdata(dev); + + if (!strncmp(buf, "enable", strlen("enable"))) + rc = device_prepare(fpc1145, true); + else if (!strncmp(buf, "disable", strlen("disable"))) + rc = device_prepare(fpc1145, false); + else + return -EINVAL; + return rc ? rc : count; +} +static DEVICE_ATTR(spi_prepare, S_IWUSR, NULL, device_prepare_set); + +/** + * sysfs node for controlling whether the driver is allowed + * to wake up the platform on interrupt. + */ +static ssize_t wakeup_enable_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} +static DEVICE_ATTR(wakeup_enable, S_IWUSR, NULL, wakeup_enable_set); + + +/** + * sysf node to check the interrupt status of the sensor, the interrupt + * handler should perform sysf_notify to allow userland to poll the node. + */ +static ssize_t irq_get(struct device *device, + struct device_attribute *attribute, + char *buffer) +{ + struct fpc1145_data *fpc1145 = dev_get_drvdata(device); + int irq = gpio_get_value(fpc1145->irq_gpio); + + return scnprintf(buffer, PAGE_SIZE, "%i\n", irq); +} + + +/** + * writing to the irq node will just drop a printk message + * and return success, used for latency measurement. + */ +static ssize_t irq_ack(struct device *device, + struct device_attribute *attribute, + const char *buffer, size_t count) +{ + struct fpc1145_data *fpc1145 = dev_get_drvdata(device); + + dev_dbg(fpc1145->dev, "%s\n", __func__); + return count; +} + +static DEVICE_ATTR(irq, S_IRUSR | S_IWUSR, irq_get, irq_ack); + +static struct attribute *attributes[] = { + &dev_attr_pinctl_set.attr, + &dev_attr_spi_prepare.attr, + &dev_attr_regulator_enable.attr, + &dev_attr_hw_reset.attr, + &dev_attr_wakeup_enable.attr, + &dev_attr_irq.attr, + NULL +}; + +static const struct attribute_group attribute_group = { + .attrs = attributes, +}; + +static irqreturn_t fpc1145_irq_handler(int irq, void *handle) +{ + struct fpc1145_data *fpc1145 = handle; + + dev_dbg(fpc1145->dev, "%s\n", __func__); + + sysfs_notify(&fpc1145->dev->kobj, NULL, dev_attr_irq.attr.name); + + return IRQ_HANDLED; +} + +static int fpc1145_request_named_gpio(struct fpc1145_data *fpc1145, + const char *label, int *gpio) +{ + struct device *dev = fpc1145->dev; + struct device_node *np = dev->of_node; + int rc = of_get_named_gpio(np, label, 0); + + if (rc < 0) { + dev_err(dev, "failed to get '%s'\n", label); + return rc; + } + *gpio = rc; + rc = devm_gpio_request(dev, *gpio, label); + if (rc) { + dev_err(dev, "failed to request gpio %d\n", *gpio); + return rc; + } + dev_dbg(dev, "%s %d\n", label, *gpio); + return 0; +} + +static int fpc1145_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int rc = 0; + size_t i; + int irqf; + struct device_node *np = dev->of_node; + + struct fpc1145_data *fpc1145 = devm_kzalloc(dev, sizeof(*fpc1145), + GFP_KERNEL); + if (!fpc1145) { + rc = -ENOMEM; + goto exit; + } + + fpc1145->dev = dev; + platform_set_drvdata(pdev, fpc1145); + + if (!np) { + dev_err(dev, "no of node found\n"); + rc = -EINVAL; + goto exit; + } + + rc = fpc1145_request_named_gpio(fpc1145, "fpc,gpio_irq", + &fpc1145->irq_gpio); + if (rc) + goto exit; + rc = fpc1145_request_named_gpio(fpc1145, "fpc,gpio_rst", + &fpc1145->rst_gpio); + if (rc) + goto exit; + + fpc1145->vcc_spi = of_property_read_bool(dev->of_node, + "vcc_spi-supply"); + fpc1145->vdd_io = of_property_read_bool(dev->of_node, + "vdd_io-supply"); + fpc1145->vdd_ana = of_property_read_bool(dev->of_node, + "vdd_ana-supply"); + + fpc1145->fingerprint_pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(fpc1145->fingerprint_pinctrl)) { + if (PTR_ERR(fpc1145->fingerprint_pinctrl) == -EPROBE_DEFER) { + dev_info(dev, "pinctrl not ready\n"); + rc = -EPROBE_DEFER; + goto exit; + } + dev_err(dev, "Target does not use pinctrl\n"); + fpc1145->fingerprint_pinctrl = NULL; + rc = -EINVAL; + goto exit; + } + + for (i = 0; i < ARRAY_SIZE(fpc1145->pinctrl_state); i++) { + const char *n = pctl_names[i]; + struct pinctrl_state *state = + pinctrl_lookup_state(fpc1145->fingerprint_pinctrl, n); + if (IS_ERR(state)) { + dev_err(dev, "cannot find '%s'\n", n); + rc = -EINVAL; + goto exit; + } + dev_info(dev, "found pin control %s\n", n); + fpc1145->pinctrl_state[i] = state; + } + + rc = select_pin_ctl(fpc1145, "fpc1145_reset_reset"); + if (rc) + goto exit; + rc = select_pin_ctl(fpc1145, "fpc1145_irq_active"); + if (rc) + goto exit; + + irqf = IRQF_TRIGGER_RISING | IRQF_ONESHOT; + mutex_init(&fpc1145->lock); + rc = devm_request_threaded_irq(dev, gpio_to_irq(fpc1145->irq_gpio), + NULL, fpc1145_irq_handler, irqf, + dev_name(dev), fpc1145); + if (rc) { + dev_err(dev, "could not request irq %d\n", + gpio_to_irq(fpc1145->irq_gpio)); + goto exit; + } + dev_dbg(dev, "requested irq %d\n", gpio_to_irq(fpc1145->irq_gpio)); + + rc = sysfs_create_group(&dev->kobj, &attribute_group); + if (rc) { + dev_err(dev, "could not create sysfs\n"); + goto exit; + } + + if (of_property_read_bool(dev->of_node, "fpc,enable-on-boot")) { + dev_info(dev, "Enabling hardware\n"); + (void)device_prepare(fpc1145, true); + } + + dev_info(dev, "%s: ok\n", __func__); +exit: + return rc; +} + +static int fpc1145_remove(struct platform_device *pdev) +{ + struct fpc1145_data *fpc1145 = platform_get_drvdata(pdev); + + sysfs_remove_group(&pdev->dev.kobj, &attribute_group); + mutex_destroy(&fpc1145->lock); + if (fpc1145->vdd_io) + (void)vreg_setup(fpc1145, "vdd_io", false); + if (fpc1145->vcc_spi) + (void)vreg_setup(fpc1145, "vcc_spi", false); + if (fpc1145->vdd_ana) + (void)vreg_setup(fpc1145, "vdd_ana", false); + dev_info(&pdev->dev, "%s\n", __func__); + return 0; +} + +static struct of_device_id fpc1145_of_match[] = { + { .compatible = "fpc,fpc1020", }, + { .compatible = "fpc,fpc1145", }, + {} +}; +MODULE_DEVICE_TABLE(of, fpc1145_of_match); + +static struct platform_driver fpc1145_driver = { + .driver = { + .name = "fpc1145", + .owner = THIS_MODULE, + .of_match_table = fpc1145_of_match, + }, + .probe = fpc1145_probe, + .remove = fpc1145_remove, +}; + +static int __init fpc1145_init(void) +{ + int rc = platform_driver_register(&fpc1145_driver); + + if (!rc) + pr_info("%s OK\n", __func__); + else + pr_err("%s %d\n", __func__, rc); + return rc; +} + +static void __exit fpc1145_exit(void) +{ + pr_info("%s\n", __func__); + platform_driver_unregister(&fpc1145_driver); +} + +module_init(fpc1145_init); +module_exit(fpc1145_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Aleksej Makarov "); +MODULE_AUTHOR("Henrik Tillman "); +MODULE_DESCRIPTION("FPC1145 Fingerprint sensor device driver."); diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index 339f94c072f478dfeb3714e6704aed390a15cc8a..d85ccab2100010679c05415de4c5e86c8b90c3a1 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -137,6 +142,8 @@ #define QPNP_PON_UVLO_DLOAD_EN BIT(7) #define QPNP_PON_SMPL_EN BIT(7) +#define QPNP_PON_DVDD_HARD_RESET_SET 0x08 + /* Ranges */ #define QPNP_PON_S1_TIMER_MAX 10256 #define QPNP_PON_S2_TIMER_MAX 2000 @@ -150,6 +157,8 @@ #define QPNP_PON_GEN2_MAX_DBC_US (USEC_PER_SEC / 4) #define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(250) +#define QPNP_RESIN_STATUS_SHORT_DELAY msecs_to_jiffies(1500) +#define QPNP_RESIN_STATUS_LONG_DELAY msecs_to_jiffies(9500) #define QPNP_PON_BUFFER_SIZE 9 @@ -202,6 +211,7 @@ struct qpnp_pon { struct pon_regulator *pon_reg_cfg; struct list_head list; struct delayed_work bark_work; + struct delayed_work resin_status_work; struct dentry *debugfs; int pon_trigger_reason; int pon_power_off_reason; @@ -229,6 +239,7 @@ module_param_named( ); static struct qpnp_pon *sys_reset_dev; +static struct qpnp_pon *sys_reset_dev_2; static DEFINE_SPINLOCK(spon_list_slock); static LIST_HEAD(spon_dev_list); @@ -298,6 +309,8 @@ static const char * const qpnp_poff_reason[] = { [39] = "Triggered from S3_RESET_KPDPWR_ANDOR_RESIN (power key and/or reset line)", }; +static unsigned long resin_status_delay; + static int qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) { @@ -853,6 +866,13 @@ qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) pon->kpdpwr_last_release_time = ktime_get(); } + if (cfg->pon_type == PON_RESIN) { + if (key_status) + schedule_delayed_work(&pon->resin_status_work, resin_status_delay); + else + cancel_delayed_work_sync(&pon->resin_status_work); + } + /* * simulate press event in case release event occurred * without a press event @@ -968,6 +988,11 @@ static irqreturn_t qpnp_pmic_wd_bark_irq(int irq, void *_pon) return IRQ_HANDLED; } +static void resin_status_work_func(struct work_struct *work) +{ + pr_err("$$$$ Stage 2 reset (RESIN) $$$$\n"); +} + static void bark_work_func(struct work_struct *work) { int rc; @@ -1803,6 +1828,180 @@ static struct kernel_param_ops smpl_en_ops = { module_param_cb(smpl_en, &smpl_en_ops, &smpl_en, 0644); +static bool resin_n_reset; + +static int qpnp_pon_debugfs_resin_n_get(char *buf, + const struct kernel_param *kp) +{ + struct qpnp_pon *pon = sys_reset_dev; + int rc = 0; + uint reg; + + if (!pon) + return -ENODEV; + + rc = regmap_read(pon->regmap,QPNP_PON_RESIN_S2_CNTL(pon), ®); + if (rc) { + dev_err(&pon->pdev->dev, + "Unable to read addr=%x, rc(%d)\n", + QPNP_PON_RESIN_S2_CNTL(pon), rc); + return rc; + } + pr_debug("ctrl:%p add:%x sid:%u reg:0x%02x\n", + to_spmi_device(pon->pdev->dev.parent)->ctrl, QPNP_PON_RESIN_S2_CNTL(pon), + to_spmi_device(pon->pdev->dev.parent)->usid, reg); + + return snprintf(buf, PAGE_SIZE, "Address 0x846:0x%02x", reg); +} + +static int qpnp_pon_debugfs_resin_n_set(const char *val, + const struct kernel_param *kp) +{ + struct qpnp_pon *pon = sys_reset_dev; + int rc = 0; + u8 reg = PON_POWER_OFF_WARM_RESET; + + if (!pon) + return -ENODEV; + + rc = param_set_bool(val, kp); + if (rc) { + pr_err("Unable to set bms_reset: %d\n", rc); + return rc; + } + + if (!*(bool *)kp->arg) + reg = QPNP_PON_DVDD_HARD_RESET_SET; + + rc = regmap_write(pon->regmap,QPNP_PON_RESIN_S2_CNTL(pon), reg); + if (rc) { + dev_err(&pon->pdev->dev, + "Unable to write to addr=%hx, rc(%d)\n", + QPNP_PON_RESIN_S2_CNTL(pon), rc); + return rc; + } + + return 0; +} + +static struct kernel_param_ops resin_n_ops = { + .set = qpnp_pon_debugfs_resin_n_set, + .get = qpnp_pon_debugfs_resin_n_get, +}; + +module_param_cb(resin_n_reset, &resin_n_ops, &resin_n_reset, 0644); + +static bool s3_timer; + +static int qpnp_pon_s3_timer_get(struct qpnp_pon *pon, uint *reg) +{ + int rc = 0; + rc = regmap_read(pon->regmap, QPNP_PON_S3_DBC_CTL(pon), reg); + if (rc) { + dev_err(&pon->pdev->dev, + "Unable to read PMIC@SID%d addr=%x, rc(%d)\n", + to_spmi_device(pon->pdev->dev.parent)->usid, + QPNP_PON_S3_DBC_CTL(pon), rc); + return rc; + } + pr_debug("PMIC@SID%d ctrl:%p add:%x reg:0x%02x\n", + to_spmi_device(pon->pdev->dev.parent)->usid, + to_spmi_device(pon->pdev->dev.parent)->ctrl, + QPNP_PON_S3_DBC_CTL(pon), *reg); + return rc; +} +static int qpnp_pon_debugfs_s3_timer_get(char *buf, + const struct kernel_param *kp) +{ + struct qpnp_pon *pon = sys_reset_dev; + struct qpnp_pon *pon2 = sys_reset_dev_2; + int rc = 0; + uint reg, reg2; + + if (!pon) + return -ENODEV; + + if (!pon2) + return -ENODEV; + + rc = qpnp_pon_s3_timer_get(pon, ®); + if (rc) + return rc; + + rc = qpnp_pon_s3_timer_get(pon2, ®2); + if (rc) + return rc; + + return snprintf(buf, PAGE_SIZE, "PMIC@SID%d:0x%02x PMIC@SID%d:0x%02x", + to_spmi_device(pon->pdev->dev.parent)->usid, reg, + to_spmi_device(pon2->pdev->dev.parent)->usid, reg2); +} + +static int qpnp_pon_s3_timer_set(struct qpnp_pon *pon, unsigned char val) +{ + int rc = 0; + + /* s3 debounce is SEC_ACCESS register */ + rc = qpnp_pon_masked_write(pon, QPNP_PON_SEC_ACCESS(pon), + 0xFF, QPNP_PON_SEC_UNLOCK); + if (rc) { + dev_err(&pon->pdev->dev, "Unable to do SEC_ACCESS rc:%d\n", + rc); + return rc; + } + + rc = qpnp_pon_masked_write(pon, QPNP_PON_S3_DBC_CTL(pon), + QPNP_PON_S3_DBC_DELAY_MASK, val); + if (rc) { + dev_err(&pon->pdev->dev, "Unable to set S3 debounce rc:%d\n", + rc); + return rc; + } + return 0; +} + +static int qpnp_pon_debugfs_s3_timer_set(const char *val, + const struct kernel_param *kp) +{ + struct qpnp_pon *pon = sys_reset_dev; + struct qpnp_pon *pon2 = sys_reset_dev_2; + int rc = 0; + + if (!pon) + return -ENODEV; + + if (!pon2) + return -ENODEV; + + rc = param_set_byte(val, kp); + + if (rc) { + pr_err("Unable to set bms_reset: %d\n", rc); + return rc; + } + + rc = qpnp_pon_s3_timer_set(pon, *(unsigned char *)kp->arg); + if (rc) { + pr_err("Unable to set s3_timer for pm: %d\n", rc); + return rc; + } + + rc = qpnp_pon_s3_timer_set(pon2, *(unsigned char *)kp->arg); + if (rc) { + pr_err("Unable to set s3_timer for pmi: %d\n", rc); + return rc; + } + + return 0; +} + +static struct kernel_param_ops s3_timer_ops = { + .set = qpnp_pon_debugfs_s3_timer_set, + .get = qpnp_pon_debugfs_s3_timer_get, +}; + +module_param_cb(s3_timer, &s3_timer_ops, &s3_timer, 0644); + static bool dload_on_uvlo; static int qpnp_pon_debugfs_uvlo_dload_get(char *buf, @@ -2001,6 +2200,7 @@ static int qpnp_pon_probe(struct platform_device *pdev) u8 s3_src_reg; unsigned long flags; uint temp = 0; + uint pon_resin_timer; pon = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_pon), GFP_KERNEL); if (!pon) @@ -2064,6 +2264,25 @@ static int qpnp_pon_probe(struct platform_device *pdev) sizeof(struct qpnp_pon_config) * pon->num_pon_config, GFP_KERNEL); + /* RESIN S1 TIMER */ + rc = regmap_read(pon->regmap, QPNP_PON_RESIN_S1_TIMER(pon), &pon_resin_timer); + if (rc) { + dev_err(&pdev->dev, "Unable to read RESIN_S1_TIMER\n"); + return rc; + } + + dev_err(&pdev->dev, "pon_resin_timer 0x%x\n", pon_resin_timer); + if (pon->num_pon_config) { + if (pon_resin_timer == 0xB) + resin_status_delay = QPNP_RESIN_STATUS_SHORT_DELAY; + else if (pon_resin_timer == 0xF) + resin_status_delay = QPNP_RESIN_STATUS_LONG_DELAY; + else { + dev_err(&pdev->dev, "invalid RESIN_S1_TIMER value\n"); + resin_status_delay = QPNP_RESIN_STATUS_LONG_DELAY; + } + } + /* Read PON_PERPH_SUBTYPE register to get PON type */ rc = regmap_read(pon->regmap, QPNP_PON_PERPH_SUBTYPE(pon), @@ -2133,6 +2352,8 @@ static int qpnp_pon_probe(struct platform_device *pdev) "PMIC@SID%d Power-on reason: Unknown and '%s' boot\n", to_spmi_device(pon->pdev->dev.parent)->usid, cold_boot ? "cold" : "warm"); + if (to_spmi_device(pon->pdev->dev.parent)->usid == 2) + sys_reset_dev_2 = pon; } else { pon->pon_trigger_reason = index; dev_info(&pon->pdev->dev, @@ -2140,6 +2361,8 @@ static int qpnp_pon_probe(struct platform_device *pdev) to_spmi_device(pon->pdev->dev.parent)->usid, qpnp_pon_reason[index], cold_boot ? "cold" : "warm"); + if (to_spmi_device(pon->pdev->dev.parent)->usid == 2) + sys_reset_dev_2 = pon; } /* POFF reason */ @@ -2253,6 +2476,7 @@ static int qpnp_pon_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, pon); INIT_DELAYED_WORK(&pon->bark_work, bark_work_func); + INIT_DELAYED_WORK(&pon->resin_status_work, resin_status_work_func); /* register the PON configurations */ rc = qpnp_pon_config_init(pon); @@ -2360,6 +2584,18 @@ static int qpnp_pon_probe(struct platform_device *pdev) "qcom,store-hard-reset-reason"); qpnp_pon_debugfs_init(pdev); + + if (pon == sys_reset_dev) { + rc = qpnp_pon_reset_config(pon, PON_POWER_OFF_WARM_RESET); + if (rc) { + dev_err(&pon->pdev->dev, + "Error configuring primary PON rc: %d\n", rc); + return rc; + } + + dev_info(&pon->pdev->dev, "Configured primary PON for warm reset\n"); + } + return 0; } diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 5be14ad29d465c5b8a6476c05ca5f81f78f06459..e7b96f1ac2c535562228c7345c251d2a6455f595 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -788,13 +788,6 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"), }, }, - { - /* Fujitsu UH554 laptop */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK UH544"), - }, - }, { } }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 2d564aabbc74ac77711553ce6c746bd72d9759b5..115b188891d30d110ffddc4ce8dd8feafac366ce 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -633,6 +633,26 @@ config TOUCHSCREEN_MIGOR To compile this driver as a module, choose M here: the module will be called migor_ts. +config TOUCHSCREEN_CLEARPAD + tristate "Synaptics ClearPad" + default n + help + Say Y here to enable Synaptics ClearPad touchscreen. + +config TOUCHSCREEN_CLEARPAD_I2C + tristate "Synaptics ClearPad I2C" + depends on I2C && TOUCHSCREEN_CLEARPAD + default n + help + Say Y here to enable Synaptics ClearPad I2C touchscreen. + +config TOUCHSCREEN_CLEARPAD_RMI_DEV + tristate "Synaptics ClearPad RMI Dev" + depends on GPIO_SYSFS && TOUCHSCREEN_CLEARPAD && TOUCHSCREEN_CLEARPAD_I2C + default n + help + Say Y here to enable Synaptics ClearPad RMI dev. + config TOUCHSCREEN_TOUCHRIGHT tristate "Touchright serial touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index f5be6fc1975145be8e14f2ef73723757f35b4380..4555e32b3e3d937384f844c555deed3a06b63243 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -19,6 +19,9 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS) += atmel_maxtouch_ts.o obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318) += chipone_icn8318.o +obj-$(CONFIG_TOUCHSCREEN_CLEARPAD) += clearpad_core.o +obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_I2C) += clearpad_i2c.o +obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV) += clearpad_rmi_dev.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o diff --git a/drivers/input/touchscreen/clearpad_core.c b/drivers/input/touchscreen/clearpad_core.c new file mode 100644 index 0000000000000000000000000000000000000000..cbc5359316059cb2150f645c6a3765445091bd29 --- /dev/null +++ b/drivers/input/touchscreen/clearpad_core.c @@ -0,0 +1,9624 @@ +/* linux/drivers/input/touchscreen/clearpad_core.c + * + * Author: Courtney Cavin + * Yusuke Yoshimura + * + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_DEBUG_FS +#include +#include +#endif +#include +#include +#include +#include +#ifdef CONFIG_FB +#include +#include +#endif +#ifdef CONFIG_ARM +#include +#endif + +#define SYN_CLEARPAD_VENDOR 0x1 +#define SYN_MAX_N_FINGERS 10 +#define SYN_DEVICE_STATUS 0x13 +#define SYN_MAX_CTRL_VALUE 80 +#define SYN_MAX_Z_VALUE 255 +#define SYN_MAX_W_VALUE 15 +#define SYN_PDT_START 0xEF +#define SYN_SIZE_OF_FD 6 +#define SYN_PAGE_SELECT_OFFSET 0xFF +#define SYN_SUPPORTED_PAGE_NUM 0x04 +#define SYN_MAX_INTERRUPT_SOURCE_COUNT 0x7 +#define SYN_STRING_LENGTH 128 +#define SYN_RETRY_NUM_OF_INITIAL_CHECK 2 +#define SYN_RETRY_NUM_OF_PROBE 3 +#define SYN_RETRY_NUM_OF_POST_PROBE 6 +#define SYN_RETRY_NUM_OF_RECOVERY 3 +#define SYN_RETRY_NUM_OF_RESET 5 +#define SYN_RETRY_NUM 3 +#define SYN_RETRY_DEFAULT_TIME_FOR_NOISE_DET 200 +#define SYN_WAIT_TIME_OF_RESET 20 +#define SYN_WAIT_TIME_AFTER_REGISTER_ACCESS 20 +#define SYN_CALIBRATION_SETUP_TIME 210 +#define SYN_CALIBRATION_WAIT 500 +#define SYN_CALIBRATION_WAIT_MS (15 * 1000) +#define SYN_CALIBRATION_EW_WAIT_MS (10 * 1000) +#define SYN_CALIBRATION_BEFORE_HWRESET_WAIT 20 +#define SYN_SINGLE_TRANSACTION_SIZE 8 +#define SYN_FP_KEY_OFFSET 6 +#define SYN_PAYLOAD_LENGTH 1 +#define SYN_DEVICE_INFO_SIZE 5 +#define SYN_DEVICE_BL_INFO_SIZE 2 +#define SYN_STAMINA_MODE_SUPPORTED_MASK 0x80000000 +#define SYN_STAMINA_REPROTRATE_SUPPORTED_MASK 0x00000001 +#define SYN_STAMINA_DOZE_HOLDOFF_SUPPORTED_MASK 0x00000002 +#define SYN_WAIT_TIME_AFTER_CHANGE_REPORTRATE 34 +#define HWTEST_SIZE_OF_COMMAND_PREFIX 2 +#define HWTEST_SIZE_OF_ONE_DIMENSION 1 +#define HWTEST_SIZE_OF_ONE_HIGH_RX 3 +#define HWTEST_SIZE_OF_TX_TO_TX_SHORT(x) (((x) + 7) / 8) +#define HWTEST_SIZE_OF_TRX_SHORT_2 7 +#define HWTEST_SIZE_OF_TRX_SHORT_2_TAB 13 +#define HWTEST_MAX_DIGITS 10 +#define HWLOG_BUF_SIZE (PAGE_SIZE * 10) +#define SYN_WAKEUP_GESTURE "wakeup_gesture" +#define WAKE_LOCK_ID "touchctrl" +#define INDENT " " +#define FLASH_DATA_CONFIGURATION_AREA_SELECT_PERM 1 +#define FLASH_DATA_CONFIGURATION_AREA_SELECT_SHIFT 13 +#define FLASH_READ_CONFIGURATION_SIZE 21 +#define FLASH_READ_FIRMWARE_INFO_SIZE_BL6X 4 +#define FLASH_READ_FIRMWARE_INFO_SIZE_BL7X 5 + +/* + * Register Offset + */ + +/* F01_RMI_CTRL05: Doze Holdoff */ +#define SYN_COVER_RECTANGLE_OFFSET 0x01 +#define SYN_EXTERNAL_REPORT_RATE_OFFSET 0x06 + +#define SYN_PAGE_ADDR(page, addr) ((page) << 8 | (addr)) +#define SYN_F_ADDR(th, func, type, reg) ((th)->pdt[func].base[type] + (reg)) +#define SYN_F_PAGE(th, func) ((th)->pdt[func].page) +#define SYN_F_PAGE_ADDR(th, func, type, reg) \ + SYN_PAGE_ADDR(SYN_F_PAGE(th, func), SYN_F_ADDR(th, func, type, reg)) +#define SYNSET(...) __VA_ARGS__ +#define SYNI(th, func, type, reg) \ + SYNSET(th, SYN_F_PAGE_ADDR(th, func, type, reg)) +#define SYNFUNC(x) SYN_##x +#define SYNTYPE(y) SYN_TYPE_##y +#define SYNF(th, func, type, reg) \ + SYNI(th, SYNFUNC(func), SYNTYPE(type), reg) +/* only F12 can use SYNA (e.g. F12_2D_CTRL) */ +#define SYNA(th, func, type, regid) \ + SYNSET(th, SYN_F_PAGE_ADDR(th, SYNFUNC(func), SYNTYPE(type), \ + ((th)->pdt[SYNFUNC(func)].offset[SYNTYPE(type)][regid]))) + +#ifdef CONFIG_DEBUG_FS +#define DEBUG_COMMAND(C0, C1) (((int)C0 << 8) + (int)C1) +#define DEBUG_ONE_BYTE_HEX 2 +#endif + +#define BIT_DEF(name, mask, shift, ...) \ +enum BIT_DEF_##name##_e { \ +name##_MASK = mask, name##_SHIFT = shift, ## __VA_ARGS__ \ +} +#define BIT_CLEAR(target, name) \ + ({ target = ((target) & ~(name##_MASK)); }) +#define BIT_SET(target, name, value) \ + ({ BIT_CLEAR(target, name); target |= ((value) << name##_SHIFT); }) +#define BIT_GET(target, name) \ + ({ (target & name##_MASK) >> name##_SHIFT; }) + +/* + * Register Bit Fields + */ + +/* F01_RMI_CMD00: Device Command */ +BIT_DEF(DEVICE_COMMAND_RESET, 0x01, 0); + +/* F01_RMI_CTRL00: Device Control */ +BIT_DEF(DEVICE_CONTROL_SLEEP_MODE, 0x03, 0, + DEVICE_CONTROL_SLEEP_MODE_NORMAL_OPERATION = 0x00, + DEVICE_CONTROL_SLEEP_MODE_SENSOR_SLEEP = 0x01, + DEVICE_CONTROL_SLEEP_MODE_SWR = 0x02); +BIT_DEF(DEVICE_CONTROL_NO_SLEEP, 0x04, 2); +BIT_DEF(DEVICE_CONTROL_CHARGER_CONNECTED, 0x20, 5); +BIT_DEF(DEVICE_CONTROL_REPORT_RATE, 0x40, 6); +BIT_DEF(DEVICE_CONTROL_CONFIGURED, 0x80, 7); + +/* F01_RMI_CTRL01_00: Interrupt Enable 0 */ +BIT_DEF(INTERRUPT_ENABLE_0, 0x3f, 0, + INTERRUPT_ENABLE_0_ENABLE_ALL = 0x3f, + INTERRUPT_ENABLE_0_DISABLE_ALL = 0x00); +BIT_DEF(INTERRUPT_ENABLE_0_FLASH, 0x01, 0); +BIT_DEF(INTERRUPT_ENABLE_0_STATUS, 0x02, 1); +BIT_DEF(INTERRUPT_ENABLE_0_ABS0, 0x04, 2); +BIT_DEF(INTERRUPT_ENALBE_0_ANALOG, 0x08, 3); +BIT_DEF(INTERRUPT_ENALBE_0_BUTTON, 0x10, 4); +BIT_DEF(INTERRUPT_ENABLE_0_SENSOR, 0x20, 5); +BIT_DEF(INTERRUPT_ENABLE_0_PRINT, 0x40, 6); + +/* F01_RMI_CTRL18: Device Control 1 */ +BIT_DEF(DEVICE_CONTROL_1_GSM_ENABLE, 0x01, 0); + +/* F01_RMI_DATA00: Device Status */ +BIT_DEF(DEVICE_STATUS_CODE, 0x0f, 0, + DEVICE_STATUS_CODE_RESET_OCCURRED = 0x01, + DEVICE_STATUS_CODE_INVALID_CONFIGURATION = 0x02, + DEVICE_STATUS_CODE_DEVICE_FAILURE = 0x03, + DEVICE_STATUS_CODE_CONFIGURATION_CRC_FAILURE = 0x04, + DEVICE_STATUS_CODE_FIRMWARE_CRC_FAILURE = 0x05, + DEVICE_STATUS_CODE_CRC_IN_PROGRESS = 0x06, + DEVICE_STATUS_CODE_GUEST_CRC_FAILURE = 0x07, + DEVICE_STATUS_CODE_EXTERNAL_AFE_FAILURE = 0x08, + DEVICE_STATUS_CODE_DISPLAY_FAILURE = 0x09); +BIT_DEF(DEVICE_STATUS_FLASH_PROG, 0x40, 6); +BIT_DEF(DEVICE_STATUS_UNCONFIGURED, 0x80, 7); + +/* F12_2D_QUERY00: General */ +BIT_DEF(GENERAL_HAS_REGISTER_DESCRIPTOR, 0x01, 0); +/* F12_2D_QUERY10_00: Supported Object Types */ +BIT_DEF(SUPPORTED_OBJECT_TYPES_HAS_GLOVED_FINGER, 0x20, 5); +BIT_DEF(SUPPORTED_OBJECT_TYPES_HAS_NARROW_OBJECT, 0x40, 6); +BIT_DEF(SUPPORTED_OBJECT_TYPES_HAS_HAND_EDGE, 0x80, 7); +/* F12_2D_QUERY10_01: Supported Object Types 2 */ +BIT_DEF(SUPPORTED_OBJECT_TYPES_HAS_COVER, 0x01, 0); +BIT_DEF(SUPPORTED_OBJECT_TYPES_HAS_STYLUS, 0x02, 1); +BIT_DEF(SUPPORTED_OBJECT_TYPES_HAS_ERASER, 0x04, 2); +BIT_DEF(SUPPORTED_OBJECT_TYPES_HAS_SMALL_OBJECT, 0x08, 3); +/* F12_2D_CTRL20_01: Report Flags */ +BIT_DEF(REPORT_FLAGS_REPORT_ALWAYS, 0x01, 0); +BIT_DEF(REPORT_FLAGS_REPORT_WAKEUP_GESTURE_ONLY, 0x02, 1); +BIT_DEF(REPORT_FLAGS_ENABLE_DRIBBLE, 0x04, 2); +/* F12_2D_CTRL23_00: Object Report Enable */ +BIT_DEF(OBJECT_REPORT_ENABLE_FINGER, 0x01, 0); +BIT_DEF(OBJECT_REPORT_ENABLE_STYLUS, 0x02, 1); +BIT_DEF(OBJECT_REPORT_ENABLE_PALM, 0x04, 2); +BIT_DEF(OBJECT_REPORT_ENABLE_UNCLASSIFIED_OBJECT, 0x08, 3); +BIT_DEF(OBJECT_REPORT_ENABLE_HOVERING_FINGER, 0x10, 4); +BIT_DEF(OBJECT_REPORT_ENABLE_GLOVED_FINGER, 0x20, 5); +BIT_DEF(OBJECT_REPORT_ENABLE_NARROW_OBJECT, 0x40, 6); +BIT_DEF(OBJECT_REPORT_ENABLE_HAND_EDGE, 0x80, 7); +/* F12_2D_CTRL23_02: Report As Finger */ +BIT_DEF(REPORT_AS_FINGER_STYLUS, 0x02, 1); +BIT_DEF(REPORT_AS_FINGER_PALM, 0x04, 2); +BIT_DEF(REPORT_AS_FINGER_UNCLASSIFIED_OBJECT, 0x08, 3); +BIT_DEF(REPORT_AS_FINGER_GLOVED_FINGER, 0x20, 5); +BIT_DEF(REPORT_AS_FINGER_NARROW_OBJECT, 0x40, 6); +BIT_DEF(REPORT_AS_FINGER_HAND_EDGE, 0x80, 7); +/* F12_2D_CTRL26: Feature Enable */ +BIT_DEF(FEATURE_ENABLE_ENABLE_GLOVED_FINGER_DETECTION, 0x01, 0); +BIT_DEF(FEATURE_ENABLE_ENABLE_CLOSED_COVER_DETECTION, 0x02, 1); +/* F12_2D_CTRL27_00: Wakeup Gesture Enable */ +BIT_DEF(WAKEUP_GESTURE_ENABLE_DOUBLE_TAP, 0x01, 0); +BIT_DEF(WAKEUP_GESTURE_ENABLE_SWIPE, 0x02, 1); +BIT_DEF(WAKEUP_GESTURE_ENABLE_TAP_AND_HOLD, 0x04, 2); +BIT_DEF(WAKEUP_GESTURE_ENABLE_CIRCLE, 0x08, 3); +BIT_DEF(WAKEUP_GESTURE_ENABLE_TRIANGLE, 0x10, 4); +BIT_DEF(WAKEUP_GESTURE_ENABLE_VEE, 0x20, 5); +BIT_DEF(WAKEUP_GESTURE_ENABLE_UNICODE, 0x40, 6); +/* F12_2D_CTRL33_00: Multi-Finger Moisture General */ +BIT_DEF(ENABLE_MULTIFINGER_MOISTURE, 0x01, 0); + +/* F34_FLASH_DATA00: Status */ +BIT_DEF(STATUS_FLASH_STATUS, 0x1F, 0, + STATUS_FLASH_STATUS_SUCCESS = 0x00, + STATUS_FLASH_STATUS_DEVICE_NOT_IN_BOOTLOADER_MODE = 0x01, + STATUS_FLASH_STATUS_INVALID_PARTITION = 0x02, + STATUS_FLASH_STATUS_INVALID_COMMAND = 0x03, + STATUS_FLASH_STATUS_INVALID_BLOCK_OFFSET = 0x04, + STATUS_FLASH_STATUS_INVALID_TRANSFER = 0x05, + STATUS_FLASH_STATUS_NOT_ERASED = 0x06, + STATUS_FLASH_STATUS_FLASH_PROGRAMMING_KEY_INCORRECT = 0x07, + STATUS_FLASH_STATUS_BAD_PARTITION_TABLE = 0x08, + STATUS_FLASH_STATUS_CHECKSUM_FAILED = 0x09, + STATUS_FLASH_STATUS_FLASH_HARDWARE_FAILURE = 0x1F); +BIT_DEF(STATUS_DEVICE_CONFIG_STATUS, 0x60, 5); +BIT_DEF(STATUS_BL_MODE, 0x80, 7); +/* F34_FLASH_DATA02: Flash Control */ +BIT_DEF(FLASH_CONTROL, 0x3F, 0, + FLASH_CONTROL_WRITE_FIRMWARE_BLOCK = 0x02, + FLASH_CONTROL_ERASE_ALL = 0x03, + FLASH_CONTROL_READ_CONFIGURATION_BLOCK = 0x05, + FLASH_CONTROL_WRITE_CONFIGURATION_BLOCK = 0x06, + FLASH_CONTROL_ERASE_CONFIGURATION = 0x07, + FLASH_CONTROL_ENABLE_FLASH_PROGRAMMING = 0x0F); +/* F34_FLASH_DATA03: Flash Status */ +BIT_DEF(FLASH_STATUS_PROGRAM_ENABLED, 0x80, 7); + +/* F51_CUSTOM_CTRL05.00: Cover */ +BIT_DEF(COVER_ENABLE, 0x01, 0); +BIT_DEF(COVER_REPORT_FINGER, 0x02, 1); + +/* F54_ANALOG_CMD00: Analog Command */ +BIT_DEF(ANALOG_COMMAND_GET_REPORT, 0x01, 0); +BIT_DEF(ANALOG_COMMAND_FORCE_CALIBRATION, 0x02, 1); +BIT_DEF(ANALOG_COMMAND_FORCE_UPDATE, 0x04, 2); + +/* F54_ANALOG_CTRL41: Multi Metric Noise Mitigation Control */ +BIT_DEF(MULTIMETRIC_NOISE_CTRL_NO_SIGNAL_CLARITY, 0x01, 0); +/* F54_ANALOG_CTRL57: 0D CBC Settings */ +BIT_DEF(CBC_SETTINGS_XMTR_CARRIER_SELECT, 0x10, 4); +/* F54_ANALOG_CTRL88: Analog Control 1 */ +BIT_DEF(ANALOG_CONTROL_1_CBC_XMTR_CARRIER_SELECT, 0x20, 5); +/* F54_ANALOG_CTRL109: General Control */ +BIT_DEF(BASELINE_CORRECTION_MODE, 0x03, 0); +/* F54_ANALOG_CTRL113: General Control */ +BIT_DEF(DISABLE_HYBRID_BASELINE, 0x2F, 5); +/* F54_ANALOG_CTRL147: General Control */ +BIT_DEF(DISABLE_HYBRID_CBC_AUTO_CORRECTION, 0x02, 1); +/* F54_ANALOG_CTRL149: Trans CBC 2 */ +BIT_DEF(TRANS_CBC_2_TRANS_CBC_GLOBAL_CAP, 0x01, 0); +/* F54_ANALOG_CTRL188: Start Calibration or Production Test */ +BIT_DEF(START_CAL_PROD_TEST_START_CALIBRATION, 0x01, 0); +BIT_DEF(START_CAL_PROD_TEST_START_IS_CALIBRATION, 0x02, 1); +BIT_DEF(START_CAL_PROD_TEST_SET_FREQUENCY, 0x0C, 2); +BIT_DEF(START_CAL_PROD_TEST_START_PROD_TEST, 0x10, 4); +BIT_DEF(START_CAL_PROD_TEST_START_SHORT_TEST_CAL, 0x60, 5); +/* F54_ANALOG_CTRL214: General Control */ +BIT_DEF(ENABLE_HYBRID_CHARGER_NOISE_MITIGATION, 0x01, 0); + +/* F54_ANALOG_DATA31: Calibration State */ +BIT_DEF(CALIBRATION_STATE_IS_CALIBRATION_CRC, 0x01, 0); +BIT_DEF(CALIBRATION_STATE_CALIBRATION_CRC, 0x02, 1); + +#define MAX_USLEEP_RANGE_IN_MS 20 + +#define LOGx(FUNC, this, X, ...) \ + FUNC(&this->pdev->dev, "(%s:%d) " X, \ + __func__, __LINE__, ## __VA_ARGS__) +#define LOGD(this, X, ...) LOGx(dev_dbg, this, X, ## __VA_ARGS__) +#define LOGI(this, X, ...) LOGx(dev_info, this, X, ## __VA_ARGS__) +#define LOGW(this, X, ...) LOGx(dev_warn, this, X, ## __VA_ARGS__) +#define LOGE(this, X, ...) LOGx(dev_err, this, X, ## __VA_ARGS__) +#define DEBUG_FLAG(this, NAME) ({ \ + bool debug_flag = false; \ + dev_dbg(&this->pdev->dev, NAME " (%d)\n", (debug_flag = true)); \ + dev_info(&this->pdev->dev, "DEBUG_FLAG " NAME " = %s", \ + debug_flag ? "true" : "false"); \ + debug_flag; \ +}) + +#define LOG_STAT(this, X, ...) LOGD(this, "stat: " X, ## __VA_ARGS__) +#define LOG_EVENT(this, X, ...) LOGD(this, "event: " X, ## __VA_ARGS__) +#define LOG_CHECK(this, X, ...) LOGD(this, "check: " X, ## __VA_ARGS__) +#define LOG_VERBOSE(this, X, ...) LOGD(this, "verbose: " X, ## __VA_ARGS__) + +#ifdef CONFIG_DEBUG_FS +#define HWLOG(this, format, ...) \ + clearpad_debug_hwtest_log(this, format, ## __VA_ARGS__) +#else +#define HWLOG(this, format, ...) +#endif +#define HWLOGx(FUNC, this, format, ...) \ +({ \ + FUNC(this, format, ## __VA_ARGS__); \ + HWLOG(this, format, ## __VA_ARGS__); \ +}) +#define HWLOGD(this, format, ...) HWLOGx(LOGD, this, format, ## __VA_ARGS__) +#define HWLOGI(this, format, ...) HWLOGx(LOGI, this, format, ## __VA_ARGS__) +#define HWLOGE(this, format, ...) HWLOGx(LOGE, this, format, ## __VA_ARGS__) +#define HWLOGW(this, format, ...) HWLOGx(LOGW, this, format, ## __VA_ARGS__) + +#define NAME_OF(NAMEARRAY, VALUE) \ + (((VALUE) < 0 || ARRAY_SIZE(NAMEARRAY) <= (VALUE)) || \ + (NAMEARRAY)[(VALUE)] == NULL ? "(unknown)" : (NAMEARRAY)[(VALUE)]) + +#define LOCK(L) \ +({ \ + LOG_STAT(this, "(will lock) <" #L ">\n"); \ + mutex_lock(&(L)->lock); \ + get_monotonic_boottime(&(L)->ts); \ + (L)->owner_func = __func__; \ + (L)->owner_line = __LINE__; \ + LOG_STAT(this, "LOCKED <" #L ">\n"); \ +}) + +#define TRYLOCK(L) \ +({ \ + int rc; \ + LOG_STAT(this, "(try lock) <" #L ">\n"); \ + rc = mutex_trylock(&(L)->lock); \ + if (rc) { \ + get_monotonic_boottime(&(L)->ts); \ + (L)->owner_func = __func__; \ + (L)->owner_line = __LINE__; \ + } \ + LOG_STAT(this, "%s <" #L ">\n", rc ? "LOCKED" : "(no lock)"); \ + rc; \ +}) + +#define UNLOCK(L) \ +({ \ + LOG_STAT(this, "UNLOCK <" #L ">\n"); \ + get_monotonic_boottime(&(L)->ts); \ + (L)->owner_func = __func__; \ + (L)->owner_line = __LINE__; \ + mutex_unlock(&(L)->lock); \ +}) + +#define IS_LOCKED(L) \ +({ \ + mutex_is_locked(&(L)->lock) ? true : false; \ +}) + + +/* + * Types + */ + +static const char * const clearpad_flash_status[] = { + [0] = "Success", + [1] = "(Reserved)", + [2] = "Flash Programming Not Enabled/Bad Command", + [3] = "Invalid Block Number", + [4] = "Block Not Erased", + [5] = "Erase Key Incorrect", + [6] = "Unknown Erase/Program Failure", + [7] = "Device has been reset", +}; + +enum clearpad_state_e { + SYN_STATE_INIT, + SYN_STATE_RUNNING, + SYN_STATE_FLASH_IMAGE_SET, + SYN_STATE_FLASH_ENABLE, + SYN_STATE_FLASH_PROGRAM, + SYN_STATE_FLASH_ERASE, + SYN_STATE_FLASH_DATA, + SYN_STATE_FLASH_CONFIG, + SYN_STATE_FLASH_DISABLE, + SYN_STATE_DISABLED, +}; + +static const char * const clearpad_state_name[] = { + [SYN_STATE_INIT] = "init", + [SYN_STATE_RUNNING] = "running", + [SYN_STATE_FLASH_IMAGE_SET] = "flash image set", + [SYN_STATE_FLASH_ENABLE] = "flash enable", + [SYN_STATE_FLASH_PROGRAM] = "flash program", + [SYN_STATE_FLASH_ERASE] = "flash erase", + [SYN_STATE_FLASH_DATA] = "flash data", + [SYN_STATE_FLASH_CONFIG] = "flash config", + [SYN_STATE_FLASH_DISABLE] = "flash disable", + [SYN_STATE_DISABLED] = "disabled", +}; + +enum clearpad_chip_e { + SYN_CHIP_3500 = 0x38, + SYN_CHIP_3330 = 0x3A, /* Hybrid incell */ + SYN_CHIP_332U = 0x40, /* Full incell */ +}; + +static const char * const clearpad_chip_name[] = { + [SYN_CHIP_3500] = "S3500", + [SYN_CHIP_3330] = "S3330", /* Hybrid incell */ + [SYN_CHIP_332U] = "S332U", /* Full incell */ +}; + +enum clearpad_function_e { + SYN_F01_RMI, + SYN_F12_2D, + SYN_F34_FLASH, + SYN_F51_CUSTOM, + SYN_F54_ANALOG, + SYN_F55_SENSOR, + SYN_N_FUNCTIONS, +}; + +static const u8 clearpad_function_value[] = { + [SYN_F01_RMI] = 0x01, + [SYN_F12_2D] = 0x12, + [SYN_F34_FLASH] = 0x34, + [SYN_F51_CUSTOM] = 0x51, + [SYN_F54_ANALOG] = 0x54, + [SYN_F55_SENSOR] = 0x55, + [SYN_N_FUNCTIONS] = 0x00, +}; + +enum clearpad_reg_type_e { + SYN_TYPE_DATA, + SYN_TYPE_CTRL, + SYN_TYPE_COMMAND, + SYN_TYPE_QUERY, + SYN_TYPE_END, +}; + +static const char * const clearpad_flash_status_name[] = { + [STATUS_FLASH_STATUS_SUCCESS] + = "Success", + [STATUS_FLASH_STATUS_DEVICE_NOT_IN_BOOTLOADER_MODE] + = "Device Not In Bootloader Mode", + [STATUS_FLASH_STATUS_INVALID_PARTITION] + = "Invalid Partition", + [STATUS_FLASH_STATUS_INVALID_COMMAND] + = "Invalid Command", + [STATUS_FLASH_STATUS_INVALID_BLOCK_OFFSET] + = "Invalid Block Offset", + [STATUS_FLASH_STATUS_INVALID_TRANSFER] + = "Invalid Transfer", + [STATUS_FLASH_STATUS_NOT_ERASED] + = "Not Erased", + [STATUS_FLASH_STATUS_FLASH_PROGRAMMING_KEY_INCORRECT] + = "Flash Programming Key Incorrect", + [STATUS_FLASH_STATUS_BAD_PARTITION_TABLE] + = "Bad Partition Table", + [STATUS_FLASH_STATUS_CHECKSUM_FAILED] + = "Checksum Failed", + [STATUS_FLASH_STATUS_FLASH_HARDWARE_FAILURE] + = "Flash Hardware Failure", +}; + +static const char * const clearpad_flash_reason_name[] = { + [DEVICE_STATUS_CODE_CONFIGURATION_CRC_FAILURE] + = "Configuration CRC Failure", + [DEVICE_STATUS_CODE_FIRMWARE_CRC_FAILURE] + = "Firmware CRC Failure", + [DEVICE_STATUS_CODE_CRC_IN_PROGRESS] + = "CRC In Progress", +}; + +enum clearpad_firmware_e { + HEADER_SIZE = 0x100, + HEADER_VERSION_OFFSET = 0x07, + HEADER_PRODUCT_ID_SIZE = 10, +}; + +enum firmware_configuration_const_e { + CONFIG_CUSTOMER_FAMILY_OFFSET, + CONFIG_FIRMWARE_REVISION_MAJOR_OFFSET, + CONFIG_FIRMWARE_REVISION_MINOR_OFFSET, + CONFIG_FIRMWARE_REVISION_EXTRA_OFFSET, + CONFIG_FIRMWARE_INFO_SIZE, +}; + +enum clearpad_container_firmware_e { + CON_TOP_START_ADDRESS_OFFSET = 0xc, + CON_CONTENT_LENGTH_OFFSET = 0x18, + CON_CONTENT_ADDRESS_OFFSET = 0x1c, + CON_START_ADDRESS_SIZE = 0x4, + CON_ID_OFFSET = 0x4, +}; + +enum firmware_partition_id_const_e { + PID_BOOTLOADER = 1, + PID_DEVICE_CONFIGURATION = 2, + PID_FLASH_CONFIGURATION = 3, + PID_MANUFACTURING_BLOCK = 4, + PID_GUEST_SERIALIZATION = 5, + PID_GLOBAL_PARAMETERS = 6, + PID_CORE_CODE = 7, + PID_CORE_CONFIGURATION = 8, + PID_DISPLAY_CONFIGURATION = 10, + PID_EXTERNAL_TOUCH_AFE_CONFIG = 11, +}; + +enum firmware_flash_command_const_e { + FLASH_CMD_IDLE, + FLASH_CMD_ENTER_BOOTLOADER, + FLASH_CMD_READ, + FLASH_CMD_WRITE, + FLASH_CMD_ERASE, + FLASH_CMD_ERASE_APPLICATION, + FLASH_CMD_SENSOR_ID, +}; + +enum firmware_container_id_const_e { + CID_CORE_CODE_CONTAINER = 0x12, + CID_CORE_CONFIGURATION_CONTAINER = 0x13, +}; + +enum firmware_bootloader_version_const_e { + BV6 = 0x06, + BV7 = 0x10, +}; + +static const int clearpad_bootloader_version_dec[] = { + [BV6] = 6, + [BV7] = 7, +}; + +enum clearpad_flash_command_e { + SYN_FORCE_FLASH, + SYN_DEFAULT_FLASH, +}; + +static const char * const clearpad_flash_command_name[] = { + [SYN_FORCE_FLASH] = "force", + [SYN_DEFAULT_FLASH] = "default", +}; + +enum clearpad_calibration_e { + SYN_CALIBRATION_NORMAL, + SYN_CALIBRATION_EW, +}; + +static const char * const clearpad_calibration_name[] = { + [SYN_CALIBRATION_NORMAL] = "normal calibration", + [SYN_CALIBRATION_EW] = "EW calibration", +}; + +struct clearpad_lock_t { + struct mutex lock; + struct timespec ts; + const char *owner_func; + int owner_line; +}; + +struct clearpad_post_probe_t { + struct delayed_work work; + bool start; + bool done; + int retry; +}; + +struct clearpad_thread_resume_t { + struct work_struct work; + struct workqueue_struct *work_queue; +}; + +struct clearpad_touchctrl_t { + struct wake_lock wakelock; + struct clearpad_lock_t session_lock; + const char *session; + int power_user; /* reference counter */ + bool will_powerdown; /* early powerdown callback has been called */ +}; + +struct clearpad_interrupt_wait_t { + const char *name; + bool use; + wait_queue_head_t wq; + atomic_t done; + int result; +}; + +struct clearpad_interrupt_t { + u32 count; + u32 wait_ms; + struct clearpad_interrupt_wait_t for_reset; + struct clearpad_interrupt_wait_t for_F34; + struct clearpad_interrupt_wait_t for_F54; + struct timespec hard_handler_ts; + struct timespec threaded_handler_ts; + struct timespec handle_first_event_ts; +}; + +enum clearpad_reset_e { + SYN_HWRESET, + SYN_SWRESET, + SYN_FORCE_HWRESET, + SYN_FORCE_SWRESET, +}; + +static const char * const clearpad_reset_name[] = { + [SYN_HWRESET] = "HW reset", + [SYN_SWRESET] = "SW reset", + [SYN_FORCE_HWRESET] = "Force HW reset", + [SYN_FORCE_SWRESET] = "Force SW reset", +}; + +struct clearpad_reset_t { + enum clearpad_reset_e mode; + struct delayed_work work; + u32 delay_for_powerup_ms; + int retry; +}; + +struct clearpad_device_info_t { + u8 manufacturer_id; + u8 product_properties; + u8 customer_family; + u8 firmware_revision_major; + u8 firmware_revision_minor; + u8 firmware_revision_extra; + u8 analog_id; + u8 product_id[HEADER_PRODUCT_ID_SIZE]; + u8 boot_loader_version_major; + u8 boot_loader_version_minor; +}; + +struct clearpad_point_t { + int id; + int x; + int y; + int wx; + int wy; + int z; + int tool; +}; + +enum clearpad_tool_e { + SYN_TOOL_FINGER = 0x01, + SYN_TOOL_PEN = 0x02, + SYN_TOOL_GLOVE = 0x03, +}; + +enum clearpad_tools_type_f12_e { + SYN_F12_TOOL_TYPE_NOOBJ, + SYN_F12_TOOL_TYPE_FINGER, + SYN_F12_TOOL_TYPE_PEN, + SYN_F12_TOOL_TYPE_PALM, + SYN_F12_TOOL_TYPE_UNCLASS, + SYN_F12_TOOL_TYPE_RESERVE, + SYN_F12_TOOL_TYPE_GLOVE, + SYN_F12_TOOL_TYPE_NARROW, + SYN_F12_TOOL_TYPE_HANDEDGE, +}; + +static const int clearpad_tool_type_f12[] = { + [SYN_F12_TOOL_TYPE_NOOBJ] = 0x00, + [SYN_F12_TOOL_TYPE_FINGER] = SYN_TOOL_FINGER, + [SYN_F12_TOOL_TYPE_PEN] = SYN_TOOL_PEN, + [SYN_F12_TOOL_TYPE_PALM] = 0x00, + [SYN_F12_TOOL_TYPE_UNCLASS] = 0x00, + [SYN_F12_TOOL_TYPE_RESERVE] = 0x00, + [SYN_F12_TOOL_TYPE_GLOVE] = SYN_TOOL_GLOVE, + [SYN_F12_TOOL_TYPE_NARROW] = 0x00, + [SYN_F12_TOOL_TYPE_HANDEDGE] = 0x00, +}; + +struct clearpad_pointer_t { + bool down; + struct clearpad_funcarea_t *funcarea; + struct clearpad_point_t cur; +}; + +struct clearpad_function_descriptor_t { + u8 number; + u8 int_count; + u8 irq_mask; + u8 page; + u8 base[SYN_TYPE_END]; + u8 offset[SYN_TYPE_END][SYN_MAX_CTRL_VALUE]; +}; + +struct clearpad_flash_block_t { + int blocks; + u32 length; + int pos; + const u8 *data; + u16 transation_count; + u16 remain_block; + u16 payload_length; + u16 block_size; +}; + +struct clearpad_flash_t { + u8 format_version; + int config_size; + u8 customer_family; + u8 firmware_revision_major; + u8 firmware_revision_minor; + u8 firmware_revision_extra; + u8 analog_id; + u8 product_id[HEADER_PRODUCT_ID_SIZE]; + struct clearpad_flash_block_t data; + struct clearpad_flash_block_t config; + const struct firmware *fw; + const char *firmware_name; + enum clearpad_flash_command_e command; + bool enter_bootloader_mode; + bool on_post_probe; + unsigned long default_timeout_ms; +}; + +struct clearpad_extents_t { + int preset_x_max, preset_y_max; + int x_min, y_min; + int x_max, y_max; + int n_fingers; + int n_bytes_per_object; +}; + +struct clearpad_charger_t { + bool supported; + bool status; +}; + +struct clearpad_pen_t { + bool supported; + bool enabled; +}; + +struct clearpad_glove_t { + bool supported; + bool enabled; +}; + +struct clearpad_cover_t { + bool supported; + bool status; + bool enabled; + int win_top; + int win_bottom; + int win_right; + int win_left; + u32 tag_x_max; + u32 tag_y_max; + u32 convert_window_size; +}; + +struct clearpad_wakeup_gesture_t { + bool supported; + bool enabled; + unsigned long time_started; + u32 timeout_delay; + bool use_workaround_for_felica; +}; + +struct clearpad_watchdog_t { + struct delayed_work work; + int delay; + bool enabled; +}; + +struct clearpad_noise_detect_t { + spinlock_t slock; + bool supported; + bool enabled; + u32 hard_handler_count; + u32 threaded_handler_count; + u32 irq_gpio_flags; + int irq_gpio; + int irq; + bool first_irq; + int retry_time_ms; + struct timespec hard_handler_ts; + struct timespec threaded_handler_ts; +}; + +struct clearpad_hwtest_t { + struct clearpad_lock_t lock; + char log_buf[HWLOG_BUF_SIZE]; + size_t log_size; +}; + +struct descriptor_t { + u16 container_id; + u8 major_version; + u8 minor_version; + u32 content_start_addr; + u32 content_len; +}; + +struct clearpad_change_reportrate_t { + bool supported; + u8 mode; +}; + +struct clearpad_doze_holdoff_t { + bool supported; + u8 default_time; + u8 glove_mode_time; + u8 cover_mode_time; +}; + +struct clearpad_stamina_mode_t { + bool supported; + bool enabled; + struct clearpad_change_reportrate_t change_reportrate; + struct clearpad_doze_holdoff_t doze_holdoff; +}; + +struct fb_t { + bool unblank_done; + bool unblank_early_done; +}; + +struct clearpad_reg_offset_t { + bool updated; + + u8 f01_cmd00; + u8 f01_ctrl00; + u8 f01_ctrl01; + u8 f01_ctrl05; + u8 f01_ctrl18; + u8 f01_data00; + u8 f01_data01; + u8 f01_query11; + + u8 f12_ctrl08; + + u8 f34_ctrl00; + u8 f34_data00; + u8 f34_data01; + u8 f34_data02; + u8 f34_data03; + u8 f34_data04; + u8 f34_data05; + u8 f34_query00; + u8 f34_query01; + u8 f34_query03; + + u8 f51_ctrl05; + u8 f51_ctrl30; + + u8 f54_cmd00; + u8 f54_ctrl41; + u8 f54_ctrl57; + u8 f54_ctrl88; + u8 f54_ctrl109; + u8 f54_ctrl113; + u8 f54_ctrl147; + u8 f54_ctrl149; + u8 f54_ctrl188; + u8 f54_ctrl214; + u8 f54_data00; + u8 f54_data01; + u8 f54_data02; + u8 f54_data03; + u8 f54_data31; + u8 f54_query38; +}; + +struct clearpad_charger_only_t { + unsigned long delay_ms; +}; + +enum clearpad_hwtest_data_type_e { + HWTEST_NULL, + HWTEST_U8, + HWTEST_S8, + HWTEST_S16, + HWTEST_U32, +}; + +enum clearpad_f54_command_e { + F54_16_IMAGE_REPORT = 2, + F54_AUTOSCAN_REPORT = 3, + F54_HIGH_RESISTANCE_REPORT = 4, + F54_RAW_CAP_RX_COUPLING_REPORT = 20, + F54_SENSOR_SPEED_REPORT = 22, + F54_TRX_TO_TRX_SHORT_2_REPORT = 26, + F54_EWMODE_RAW_CAP_REPORT = 38, + F54_ABS_RAW_REPORT = 63, + F54_FULLINCELL_RAW_CAP_REPORT = 83, + F54_FULLINCELL_CAL_DATA_CHK_REPORT = 84, + F54_FULLINCELL_SENSOR_SPEED_REPORT = 86, + F54_TRX_TO_TRX_SHORT_RAW_IMAGE_REPORT = 100, +}; + +enum clearpad_f12_2d_reporting_control_e { + F12_2D_CTRL_MOTION_SUPP_X = 0, + F12_2D_CTRL_MOTION_SUPP_Y, + F12_2D_CTRL_RPT_FLAG, + F12_2D_CTRL_HOVER_RPT, + F12_2D_CTRL_RPT_REG_MAX +}; + +enum clearpad_f12_2d_object_report_enable_e { + F12_2D_CTRL_OBJ_REPORT_ENABLE = 0, + F12_2D_CTRL_MAX_OBJ_REPORT, + F12_2D_CTRL_REPORT_AS_FINGER +}; + +enum clearpad_f12_2d_data_registers_id_e { + F12_2D_DATA_SENSED_OBJECTS = 1, + F12_2D_DATA_OBJ_ATTENTION = 15, + F12_2D_DATA_REG_MAX +}; + +enum clearpad_force_sleep_e { + FSMODE_OFF = 0, /* Normal suspend/resume */ + FSMODE_KEEP = 1, /* Sleep forever */ + FSMODE_ONESHOT = 2, /* Oneshot (will be FSMODE_OFF by resume) */ +}; + +struct clearpad_t { + enum clearpad_state_e state; + enum clearpad_chip_e chip_id; + struct input_dev *input; + struct platform_device *pdev; + struct clearpad_platform_data_t *pdata; + struct clearpad_bus_data_t *bdata; + struct clearpad_lock_t lock; + struct clearpad_touchctrl_t touchctrl; + struct clearpad_post_probe_t post_probe; + struct clearpad_thread_resume_t thread_resume; + struct clearpad_device_info_t device_info; + struct clearpad_funcarea_t *funcarea; + struct clearpad_pointer_t pointer[SYN_MAX_N_FINGERS]; + struct clearpad_function_descriptor_t pdt[SYN_N_FUNCTIONS]; + struct clearpad_flash_t flash; + struct clearpad_wakeup_gesture_t wakeup_gesture; + struct clearpad_charger_t charger; + struct clearpad_pen_t pen; + struct clearpad_glove_t glove; + struct clearpad_cover_t cover; + struct clearpad_extents_t extents; + struct clearpad_reset_t reset; + struct clearpad_noise_detect_t noise_det; + struct clearpad_interrupt_t interrupt; + struct clearpad_stamina_mode_t stamina; + struct clearpad_reg_offset_t reg_offset; + struct clearpad_charger_only_t charger_only; + int irq; + bool irq_enabled; + enum clearpad_force_sleep_e force_sleep; +#ifdef CONFIG_FB + struct notifier_block fb_notif; +#endif + char fwname[SYN_STRING_LENGTH + 1]; + char result_info[SYN_STRING_LENGTH + 1]; + bool flash_requested; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; + struct clearpad_hwtest_t hwtest; +#endif + u32 flip_config; + u32 touch_pressure_enabled; + u32 touch_size_enabled; + u32 touch_orientation_enabled; + bool calibration_supported; + bool calibrate_on_fwflash; + struct device_node *evdt_node; + struct clearpad_watchdog_t watchdog; + spinlock_t slock; + bool dev_active; + bool dev_busy; + bool early_suspend; /* suspend mode has been set from early suspend */ + bool irq_pending; + bool last_irq; + + bool is_sol; + + struct fb_t wakeup; +}; + +/* + * Function prototypes + */ + +static void clearpad_update_chip_id(struct clearpad_t *this); +static void clearpad_set_is_sol(struct clearpad_t *this); +static void clearpad_post_probe_work(struct work_struct *work); +static void clearpad_thread_resume_work(struct work_struct *work); +static void clearpad_funcarea_initialize(struct clearpad_t *this); +static int clearpad_handle_if_first_event(struct clearpad_t *this); +static void clearpad_reset(struct clearpad_t *this, + enum clearpad_reset_e mode, const char *cause); +static void clearpad_funcarea_invalidate_all(struct clearpad_t *this); +static int clearpad_set_resume_mode(struct clearpad_t *this); +static int clearpad_set_suspend_mode(struct clearpad_t *this); +static int clearpad_read_pca_block(struct clearpad_t *this, + u16 block_num, u8 *data); +static int clearpad_write_pca_block(struct clearpad_t *this, + u16 block_num, u8 *data); +static int clearpad_process_irq(struct clearpad_t *this); +static int clearpad_flash(struct clearpad_t *this); +static bool clearpad_process_noise_det_irq(struct clearpad_t *this); +static void clearpad_touch_config_dt_for_chip_id(struct clearpad_t *this, + int chip_id); +#ifdef CONFIG_DEBUG_FS +static int clearpad_debug_hwtest_log(struct clearpad_t *this, + const char *format, ...); +static void clearpad_debug_info(struct clearpad_t *this); +#endif + +/* + * Functions + */ + +static inline bool is_equal_cstring(const char *a, const char *b) +{ + size_t length = max(strnlen(a, PAGE_SIZE), strnlen(b, PAGE_SIZE)); + + return strncmp(a, b, length) == 0; +} + +static char *clearpad_s(u8 *array, size_t size) +{ + static char string[SYN_STRING_LENGTH + 1]; + + memset(string, 0, SYN_STRING_LENGTH + 1); + size = (SYN_STRING_LENGTH < size) ? SYN_STRING_LENGTH : size; + memcpy(string, array, size); + + return string; +} + +static void clearpad_set_delay(unsigned long ms) +{ + if (ms > 0) + ms <= MAX_USLEEP_RANGE_IN_MS ? + usleep_range(ms * 1000, (ms * 1000) + 1000) : msleep(ms); +} + +static inline bool clearpad_is_valid_function(struct clearpad_t *this, int func) +{ + return (0 <= func && func < SYN_N_FUNCTIONS) + && (this->pdt[func].number == clearpad_function_value[func]); +} + +/* need LOCK(&this->lock) */ +static void clearpad_set_irq(struct clearpad_t *this, bool enable) +{ + if (enable && !this->irq_enabled) { + enable_irq(this->irq); + LOGI(this, "irq was enabled\n"); + } else if (!enable && this->irq_enabled) { + disable_irq_nosync(this->irq); + LOGI(this, "irq was disabled\n"); + } else { + LOGI(this, "no irq change (%s)\n", + this->irq_enabled ? "enable" : "disable"); + } + this->irq_enabled = enable; +} + +static int clearpad_set_noise_det_irq(struct clearpad_t *this, bool enable, + bool set_first_irq) +{ + int ret = 0; + unsigned long flags; + + if (this->noise_det.supported && this->chip_id == SYN_CHIP_332U) { + spin_lock_irqsave(&this->noise_det.slock, flags); + if (enable && set_first_irq) + this->noise_det.first_irq = true; + if (enable && !this->noise_det.enabled) { + enable_irq(this->noise_det.irq); + } else if (!enable && this->noise_det.enabled) { + disable_irq_nosync(this->noise_det.irq); + } else { + spin_unlock_irqrestore(&this->noise_det.slock, flags); + ret = -1; + goto end; + } + this->noise_det.enabled = enable; + spin_unlock_irqrestore(&this->noise_det.slock, flags); + } else { + ret = -1; + } +end: + return ret; +} + +/* need LOCK(&this->lock) */ +static void clearpad_notify_interrupt(struct clearpad_t *this, + struct clearpad_interrupt_wait_t *wait, + int result) +{ + if (wait->use) { + LOGI(this, "handled interrupt '%s' (rc=%d)\n", + wait->name, result); + atomic_inc(&wait->done); + wait->result = result; + wake_up_all(&wait->wq); + } +} + +/* need LOCK(&this->lock) */ +static void clearpad_prepare_for_interrupt(struct clearpad_t *this, + struct clearpad_interrupt_wait_t *wait, + const char *name) +{ + if (wait->use) + LOGE(this, "already used '%s' (%s)\n", wait->name, name); + + wait->name = name; + wait->use = true; + atomic_set(&wait->done, 0); +} + +/* need LOCK(&this->lock) */ +static void clearpad_undo_prepared_interrupt(struct clearpad_t *this, + struct clearpad_interrupt_wait_t *wait, + const char *name) +{ + if (is_equal_cstring(wait->name, name)) { + LOGE(this, "undo prepared interrupt %s\n", wait->name); + wait->name = NULL; + wait->use = false; + } +} + +/* NO need LOCK(&this->lock) */ +static int clearpad_wait_for_interrupt(struct clearpad_t *this, + struct clearpad_interrupt_wait_t *wait, + unsigned long ms) +{ + int rc; + int retry = 0; + + LOG_STAT(this, "(wait for interrupt) <%s>\n", wait->name); +retry: + rc = wait_event_timeout(wait->wq, + atomic_read(&wait->done), msecs_to_jiffies(ms)); + if (rc == 0) { + LOGW(this, "timeout '%s' (retry %d)\n", wait->name, retry); + rc = -ETIMEDOUT; + if (retry++ < SYN_RETRY_NUM) + goto retry; + } else if (rc < 0) { + LOGE(this, "failed to wait for '%s' (rc=%d done=%d)", + wait->name, rc, atomic_read(&wait->done)); + } else { + LOG_STAT(this, "received interrupt <%s> (done=%d)\n", + wait->name, atomic_read(&wait->done)); + rc = 0; + } + + LOCK(&this->lock); + wait->name = NULL; + wait->use = false; + if (!rc) + rc = wait->result; + UNLOCK(&this->lock); + + return rc; +} + +/* + * touchctrl : porting for exported functions + */ + +static int touchctrl_hwreset(struct clearpad_t *this, int mode) +{ + int rc = 0; + int raw_mode = 0; + int retry; + + LOGI(this, "execute '%s'\n", NAME_OF(clearpad_reset_name, mode)); + this->wakeup.unblank_done = false; + this->wakeup.unblank_early_done = false; + switch (mode) { + case SYN_HWRESET: + case SYN_FORCE_HWRESET: + raw_mode = INCELL_DISPLAY_HW_RESET; + break; + default: + LOGE(this, "unknown HW reset mode (%d)\n", mode); + return -EINVAL; + } + + for (retry = 0; retry < SYN_RETRY_NUM; retry++) { + rc = incell_control_mode(raw_mode, INCELL_FORCE); + if (rc != INCELL_EBUSY) + break; + } + + return rc; +} + +static int touchctrl_display_off(struct clearpad_t *this) +{ + int rc = 0; + int retry; + + LOGI(this, "turn display off\n"); + this->wakeup.unblank_done = false; + this->wakeup.unblank_early_done = false; + for (retry = 0; retry < SYN_RETRY_NUM; retry++) { + rc = incell_control_mode(INCELL_DISPLAY_OFF, INCELL_FORCE); + if (rc != INCELL_EBUSY) + break; + } + + return rc; +} + +static bool touchctrl_is_touch_powered(struct clearpad_t *this) +{ + incell_pw_status status = { false, false }; + int rc; + + rc = incell_get_power_status(&status); + if (rc) + LOGE(this, "failed to get power status\n"); + else + LOGD(this, "power status (touch %s, display %s)\n", + status.touch_power ? "ON" : "OFF", + status.display_power ? "ON" : "OFF"); + + return rc == 0 && status.touch_power; +} + +static bool touchctrl_is_display_powered(struct clearpad_t *this) +{ + incell_pw_status status = { false, false }; + int rc; + + rc = incell_get_power_status(&status); + if (rc) + LOGE(this, "failed to get power status\n"); + else + LOGD(this, "power status (touch %s, display %s)\n", + status.touch_power ? "ON" : "OFF", + status.display_power ? "ON" : "OFF"); + + return rc == 0 && status.display_power; +} + +/* + * need LOCK(&this->lock) + * + * @return true : locked with specified condition + * false : not locked + */ +static bool touchctrl_lock_power(struct clearpad_t *this, const char *id, + bool need_touch_power, bool need_display_power) +{ + struct clearpad_touchctrl_t *touchctrl = &this->touchctrl; + incell_pw_status status = { false, false }; + int rc; + bool result = false; + + LOG_STAT(this, "(will lock power) <%s>\n", id); + + if (touchctrl->power_user != 0) { + rc = incell_get_power_status(&status); + if (rc) + LOGE(this, "failed to get power status (rc=%d)\n", rc); + goto check_condition; + } + + /* stop lock if it will be powered down */ + if (!this->wakeup_gesture.enabled && touchctrl->will_powerdown) { + LOG_STAT(this, "(no lock) will be powered down <%s>\n", id); + goto err_in_condition_of_powerdown; + } + + /* the first user locks power */ + rc = incell_power_lock_ctrl(INCELL_DISPLAY_POWER_LOCK, &status); + switch (rc) { + case INCELL_OK: + break; + case INCELL_ALREADY_LOCKED: + LOGW(this, "already locked <%s>\n", id); + WARN_ON(rc == INCELL_ALREADY_LOCKED); + break; + default: + LOGE(this, "failed to lock power(%d) <%s>\n", rc, id); + goto err_in_power_lock_ctrl; + } + +check_condition: + if ((need_touch_power && !status.touch_power) || + (need_display_power && !status.display_power)) { + LOG_STAT(this, "(no lock) power due to condition) <%s> " + "touch=%s(%s) display=%s(%s)\n", id, + status.touch_power ? "On" : "Off", + need_touch_power ? "required" : "optional", + status.display_power ? "On" : "Off", + need_display_power ? "required" : "optional"); + if (incell_power_lock_ctrl(INCELL_DISPLAY_POWER_UNLOCK, + &status)) + LOGE(this, "failed to unlock power\n"); + rc = 0; + goto err_in_locked_power_status; + } + result = true; + touchctrl->power_user += 1; + LOG_STAT(this, "LOCKED power <%s> (%d)\n", id, touchctrl->power_user); +err_in_locked_power_status: +err_in_power_lock_ctrl: +err_in_condition_of_powerdown: + return result; +} + +/* need LOCK(&this->lock) */ +static void touchctrl_unlock_power(struct clearpad_t *this, const char *id) +{ + struct clearpad_touchctrl_t *touchctrl = &this->touchctrl; + incell_pw_status status = { false, false }; + int rc; + unsigned long flags; + + LOG_STAT(this, "unlock power for touch <%s>\n", id); + + if (this->last_irq && is_equal_cstring(id, "irq_handler")) { + LOGD(this, "last pending IRQ handled\n"); + this->last_irq = false; + touchctrl->power_user -= 1; + } + + touchctrl->power_user -= 1; + if (touchctrl->power_user > 0) { + LOG_STAT(this, "UNLOCKED power <%s> user(%d)\n", + id, touchctrl->power_user); + goto unlocked; + } else if (touchctrl->power_user < 0) { + LOGE(this, "invalid unlock <%s> user(%d)\n", + id, touchctrl->power_user); + touchctrl->power_user = 0; + } + + /* suspend when the last user unlocks power */ + if (touchctrl->will_powerdown) { + if (this->dev_active) { + rc = clearpad_set_suspend_mode(this); + if (rc) + LOGE(this, "failed to suspend\n"); + + if (this->watchdog.enabled) + cancel_delayed_work(&this->watchdog.work); + cancel_delayed_work(&this->reset.work); + } + /* check for pending IRQ on suspend mode */ + if (!this->dev_active) { + spin_lock_irqsave(&this->slock, flags); + if (unlikely(this->dev_busy || this->irq_pending)) { + touchctrl->power_user += 1; + this->last_irq = true; + spin_unlock_irqrestore(&this->slock, flags); + LOGD(this, "there is a pending IRQ, " + "will not yet Unlock Power\n"); + goto unlocked_with_pending_irq; + } + spin_unlock_irqrestore(&this->slock, flags); + } + } + + rc = incell_power_lock_ctrl(INCELL_DISPLAY_POWER_UNLOCK, &status); + switch (rc) { + case INCELL_OK: + break; + case INCELL_ALREADY_UNLOCKED: + LOGW(this, "already unlocked <%s>\n", id); + break; + default: + LOGE(this, "failed to unlock power(%d) <%s>\n", rc, id); + goto err_in_power_lock_ctrl; + } + LOG_STAT(this, "UNLOCKED power <%s> touch=%s display=%s\n", id, + status.touch_power ? "On" : "Off", + status.display_power ? "On" : "Off"); + +err_in_power_lock_ctrl: +unlocked_with_pending_irq: +unlocked: + return; +} + +static void touchctrl_notify_wakeup_gesture_mode(struct clearpad_t *this, + bool enabled) +{ + LOG_STAT(this, "%s\n", enabled ? "enable" : "disable"); + + incell_ewu_mode_ctrl(enabled ? INCELL_DISPLAY_EWU_ENABLE + : INCELL_DISPLAY_EWU_DISABLE); +} + +/* Begin a session to use touch device requiring power supply */ +static int clearpad_ctrl_session_begin(struct clearpad_t *this, + const char *session) +{ + struct clearpad_touchctrl_t *touchctrl = &this->touchctrl; + int rc = 0; + + wake_lock(&touchctrl->wakelock); + LOCK(&touchctrl->session_lock); + LOGI(this, "begin '%s' session\n", session); + touchctrl->session = session; + + LOCK(&this->lock); + /* keep touch power for this session */ + if (!touchctrl_lock_power(this, session, true, false)) { + LOGE(this, "failed to lock power\n"); + rc = -EAGAIN; + goto err_in_lock_power; + } + rc = clearpad_handle_if_first_event(this); + if (rc < 0) { + LOGE(this, "failed to handle first event\n"); + rc = -EBUSY; + goto err_in_first_event_handling; + } else { + rc = 0; + } + UNLOCK(&this->lock); + goto end; + +err_in_first_event_handling: + touchctrl_unlock_power(this, session); +err_in_lock_power: + UNLOCK(&this->lock); + touchctrl->session = NULL; + UNLOCK(&touchctrl->session_lock); + wake_unlock(&touchctrl->wakelock); +end: + return rc; +} + +/* End a session to use touch device requiring power supply */ +static void clearpad_ctrl_session_end(struct clearpad_t *this, + const char *session) +{ + struct clearpad_touchctrl_t *touchctrl = &this->touchctrl; + + if (touchctrl->session == NULL || + !is_equal_cstring(touchctrl->session, session)) { + LOGW(this, "try invalid session end '%s' (current '%s')", + session, touchctrl->session); + } + + /* release power for this session */ + LOCK(&this->lock); + touchctrl_unlock_power(this, session); + UNLOCK(&this->lock); + + LOGI(this, "end '%s' session\n", session); + touchctrl->session = NULL; + UNLOCK(&touchctrl->session_lock); + wake_unlock(&touchctrl->wakelock); +} + +/* + * Basic bus access + */ + +static int clearpad_set_page(struct clearpad_t *this, u8 page) +{ + return this->bdata->set_page(this->pdev->dev.parent, page); +} + +static int clearpad_read(struct clearpad_t *this, u16 addr, + u8 *buf, int len) +{ + return this->bdata->read(this->pdev->dev.parent, addr, buf, len); +} + +static int clearpad_write(struct clearpad_t *this, u16 addr, + const u8 *buf, u8 len) +{ + return this->bdata->write(this->pdev->dev.parent, addr, buf, len); +} + +static int clearpad_read_block(struct clearpad_t *this, u16 addr, + u8 *buf, int len) +{ + return this->bdata->read_block(this->pdev->dev.parent, + addr, buf, len); +} + +static int clearpad_write_block(struct clearpad_t *this, u16 addr, + const u8 *buf, int len) +{ + return this->bdata->write_block(this->pdev->dev.parent, + addr, buf, len); +} + +/* + * Read/Write data of specific size + */ + +static int clearpad_get(struct clearpad_t *this, u16 addr, u8 *val) +{ + int rc = clearpad_read(this, addr, val, 1); + return rc == 1 ? 0 : (rc < 0 ? rc : -EIO); +} + +static int clearpad_put(struct clearpad_t *this, u16 addr, u8 val) +{ + int rc = clearpad_write(this, addr, &val, 1); + return rc == 1 ? 0 : (rc < 0 ? rc : -EIO); +} + +static int clearpad_put_bit(struct clearpad_t *this, u16 addr, u8 val, u8 mask) +{ + int rc; + u8 buf; + + rc = clearpad_get(this, addr, &buf); + if (rc) + goto end; + + buf = (buf & ~mask) | val; + rc = clearpad_put(this, addr, buf); +end: + return rc; +} + +static int clearpad_get_block(struct clearpad_t *this, u16 addr, + u8 *buf, int len) +{ + int rc; + + rc = clearpad_read_block(this, addr, buf, len); + return rc == len ? 0 : (rc < 0 ? rc : -EIO); +} + +static int clearpad_put_block(struct clearpad_t *this, u16 addr, + const u8 *buf, int len) +{ + int rc; + + rc = clearpad_write_block(this, addr, buf, len); + return rc == len ? 0 : (rc < 0 ? rc : -EIO); +} + +static int clearpad_set_doze_holdoff_time(struct clearpad_t *this, + u8 holdoff_time) +{ + int rc = 0; + u8 current_time = 0x00; + + if (!this->stamina.supported) { + LOGI(this, "stamina mode is not supported\n"); + goto end; + } + if (!this->stamina.doze_holdoff.supported) { + LOGI(this, "doze holdoff is not supported\n"); + goto end; + } + + if (clearpad_get( + SYNF(this, F01_RMI, CTRL, this->reg_offset.f01_ctrl05), + ¤t_time)) { + LOGE(this, "failed to get current Doze Holdoff\n"); + rc = -EINVAL; + goto end; + } + if (current_time == holdoff_time) { + LOGI(this, "new Doze Holdoff is same as current=0x%02x\n", + current_time); + goto end; + } + + /* F01_RMI_CTRL05: Doze Holdoff */ + rc = clearpad_put( + SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl05), + holdoff_time); + if (rc) { + LOGE(this, "failed to set new Doze Holdoff=0x%02x\n", + holdoff_time); + goto end; + } + /* F54_ANALOG_CMD00: Analog Command */ + rc = clearpad_put( + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + ANALOG_COMMAND_FORCE_UPDATE_MASK); + if (rc) { + LOGE(this, "failed to set force update\n"); + goto end; + } + LOGI(this, "changed Doze Holdoff=0x%02x\n", holdoff_time); + +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_set_doze_holdoff(struct clearpad_t *this) +{ + int rc = 0; + u8 holdoff_time = 0x00; + + if (!this->stamina.supported) { + LOGI(this, "stamina mode is not supported\n"); + goto end; + } + if (!this->stamina.doze_holdoff.supported) { + LOGI(this, "doze holdoff is not supported\n"); + goto end; + } + + LOGI(this, "glove mode: %s, cover mode/status: %s/%s\n", + this->glove.enabled ? "enable" : "disable", + this->cover.enabled ? "enable" : "disable", + this->cover.status ? "CLOSE" : "OPEN"); + + holdoff_time = this->stamina.doze_holdoff.default_time; + if (this->glove.enabled) + holdoff_time = this->stamina.doze_holdoff.glove_mode_time; + if (this->cover.enabled && this->cover.status) + holdoff_time = this->stamina.doze_holdoff.cover_mode_time; + + rc = clearpad_set_doze_holdoff_time(this, holdoff_time); + if (rc) + goto end; + +end: + return rc; +} + +static struct clearpad_funcarea_t clearpad_default_funcarea_array[] = { + { + { 0, 0, 0, 0}, { 0, 0, 0, 0}, + SYN_FUNCAREA_POINTER, NULL + }, + { .func = SYN_FUNCAREA_END } +}; + +static struct clearpad_funcarea_t *clearpad_funcarea_get( + struct clearpad_t *this, u8 module_id, u8 rev) +{ + clearpad_default_funcarea_array[0].original.x2 = + this->extents.preset_x_max; + clearpad_default_funcarea_array[0].original.y2 = + this->extents.preset_y_max; + clearpad_default_funcarea_array[0].extension.x2 = + this->extents.preset_x_max; + clearpad_default_funcarea_array[0].extension.y2 = + this->extents.preset_y_max; + return clearpad_default_funcarea_array; +} + +static int clearpad_read_pdt(struct clearpad_t *this) +{ + struct clearpad_function_descriptor_t fdes; + u8 addr = SYN_PDT_START - 1; + u8 irq_bit = 0; + u8 page = 0; + int i, j, k; + int rc; + + memset(&this->pdt, 0, sizeof(*this->pdt) * SYN_N_FUNCTIONS); + for (i = 0; i < SYN_N_FUNCTIONS && addr >= SYN_SIZE_OF_FD - 1;) { + rc = clearpad_get(this, SYN_PAGE_ADDR(page, addr--), + &fdes.number); + if (rc) + break; + rc = clearpad_get(this, SYN_PAGE_ADDR(page, addr--), + &fdes.int_count); + if (rc) + break; + fdes.int_count &= SYN_MAX_INTERRUPT_SOURCE_COUNT; + for (fdes.irq_mask = 0, j = 0; j < fdes.int_count; j++) + fdes.irq_mask |= (1 << irq_bit++); + rc = clearpad_get(this, SYN_PAGE_ADDR(page, addr--), + &fdes.base[SYN_TYPE_DATA]); + if (rc) + break; + rc = clearpad_get(this, SYN_PAGE_ADDR(page, addr--), + &fdes.base[SYN_TYPE_CTRL]); + if (rc) + break; + rc = clearpad_get(this, SYN_PAGE_ADDR(page, addr--), + &fdes.base[SYN_TYPE_COMMAND]); + if (rc) + break; + rc = clearpad_get(this, SYN_PAGE_ADDR(page, addr--), + &fdes.base[SYN_TYPE_QUERY]); + if (rc) + break; + fdes.page = page; + LOG_CHECK(this, "F%02x_IRQ_MASK = %02x\n", + fdes.number, fdes.irq_mask); + LOG_CHECK(this, "F%02x_DATA = %02x\n", + fdes.number, fdes.base[SYN_TYPE_DATA]); + LOG_CHECK(this, "F%02x_CTRL = %02x\n", + fdes.number, fdes.base[SYN_TYPE_CTRL]); + LOG_CHECK(this, "F%02x_COMMAND = %02x\n", + fdes.number, fdes.base[SYN_TYPE_COMMAND]); + LOG_CHECK(this, "F%02x_QUERY = %02x\n", + fdes.number, fdes.base[SYN_TYPE_QUERY]); + LOG_CHECK(this, "F%02x Page = %02x\n", + fdes.number, fdes.page); + if (!fdes.number) { + if (page < SYN_SUPPORTED_PAGE_NUM) { + addr = SYN_PDT_START - 1; + page += 1; + continue; + } + break; + } + for (k = 0; k < SYN_N_FUNCTIONS; k++) { + if (clearpad_function_value[k] == fdes.number) { + if (!this->pdt[k].number) + memcpy(&this->pdt[k], &fdes, + sizeof(*this->pdt)); + i++; + HWLOGI(this, "F%02x page:0x%02x " + "base[DATA:0x%02x " + "CTRL:0x%02x COMMAND:0x%02x " + "QUERY:0x%02x] irq:0x%02x\n", + fdes.number, + fdes.page, + fdes.base[SYN_TYPE_DATA], + fdes.base[SYN_TYPE_CTRL], + fdes.base[SYN_TYPE_COMMAND], + fdes.base[SYN_TYPE_QUERY], + fdes.irq_mask); + break; + } + } + } + + return rc; +} + +/* + * Charger + */ + +static int clearpad_set_charger(struct clearpad_t *this) +{ + int rc = 0; + + if (!this->charger.supported) + goto end; + + if (this->charger.status) + /* F01_RMI_CTRL00: Device Command */ + rc = clearpad_put_bit( + SYNF(this, F01_RMI, CTRL, this->reg_offset.f01_ctrl00), + DEVICE_CONTROL_CHARGER_CONNECTED_MASK, + DEVICE_CONTROL_CHARGER_CONNECTED_MASK); + else + /* F01_RMI_CTRL00: Device Command */ + rc = clearpad_put_bit( + SYNF(this, F01_RMI, CTRL, this->reg_offset.f01_ctrl00), + 0, DEVICE_CONTROL_CHARGER_CONNECTED_MASK); + if (rc) + LOGE(this, "failed to set charger status"); +end: + return rc; +} + +/* + * Pen + */ + +static int clearpad_set_pen(struct clearpad_t *this) +{ + int rc = 0; + + if (!this->pen.supported) + goto end; + + if (!clearpad_is_valid_function(this, SYN_F12_2D)) { + LOGE(this, "F12 is required to set pen\n"); + rc = -EPERM; + goto end; + } + + /* F12_2D_CTRL23_00: Object Report Enable */ + rc = clearpad_put_bit(SYNA(this, F12_2D, CTRL, 23), + this->pen.enabled ? + OBJECT_REPORT_ENABLE_STYLUS_MASK : 0, + OBJECT_REPORT_ENABLE_STYLUS_MASK); +end: + if (rc) + LOGE(this, "failed to set pen"); + return rc; +} + +/* + * Glove finger register in touch ic + */ + +static int clearpad_set_glove_finger_reg(struct clearpad_t *this, bool enable) +{ + int rc = 0; + + /* F12_2D_CTRL23_00: Object Report Enable */ + rc = clearpad_put_bit(SYNA(this, F12_2D, CTRL, 23), + enable ? + OBJECT_REPORT_ENABLE_GLOVED_FINGER_MASK : 0, + OBJECT_REPORT_ENABLE_GLOVED_FINGER_MASK); + if (rc) { + LOGE(this, "error in setting for object report enable\n"); + goto end; + } + if (this->chip_id == SYN_CHIP_3330 || + this->chip_id == SYN_CHIP_332U) { + /* F12_2D_CTRL26: Feature Enable */ + rc = clearpad_put_bit(SYNA(this, F12_2D, CTRL, 26), + enable ? + FEATURE_ENABLE_ENABLE_GLOVED_FINGER_DETECTION_MASK : 0, + FEATURE_ENABLE_ENABLE_GLOVED_FINGER_DETECTION_MASK); + if (rc) { + LOGE(this, "error in setting for feature enable\n"); + goto end; + } + } +end: + if (rc) + LOGE(this, "failed to set glove finger register in touch ic \n"); + return rc; +} + +/* + * Glove + */ + +static int clearpad_set_glove_mode(struct clearpad_t *this, bool enable) +{ + int rc = 0; + u8 buf; + + if (!this->glove.supported) + goto end; + + if (!clearpad_is_valid_function(this, SYN_F12_2D)) { + LOGE(this, "F12 is required to set glove mode\n"); + rc = -EPERM; + goto end; + } + + /* F12_2D_QUERY10: Supported Object Types */ + rc = clearpad_get(SYNA(this, F12_2D, QUERY, 10), &buf); + if (rc) { + LOGE(this, "failed to get supported types"); + goto end; + } + if (!BIT_GET(buf, SUPPORTED_OBJECT_TYPES_HAS_GLOVED_FINGER)) { + LOGI(this, "glove mode is not supported\n"); + goto end; + } + + /* Set glove finger register in touch ic */ + if (!this->cover.status) { + rc = clearpad_set_glove_finger_reg(this, enable); + if (rc) + goto end; + rc = clearpad_set_doze_holdoff(this); + if (rc) + LOGE(this, "failed to set Doze Holdoff\n"); + } +end: + if (rc) + LOGE(this, "failed to set glove mode"); + return rc; +} + +/* + * Smart Cover + */ + +static int clearpad_set_cover_status(struct clearpad_t *this) +{ + int rc = 0; + size_t buf_size = 3; + u8 buf[buf_size]; + + if (!clearpad_is_valid_function(this, SYN_F12_2D) && + !clearpad_is_valid_function(this, SYN_F51_CUSTOM) && + !clearpad_is_valid_function(this, SYN_F54_ANALOG)) { + LOGE(this, "F12, F51 and F54 are required to set cover status"); + rc = -EPERM; + goto end; + } + + switch (this->chip_id) { + case SYN_CHIP_3330: + case SYN_CHIP_332U: + /* F12_2D_CTRL26: Feature Enable */ + rc = clearpad_put_bit(SYNA(this, F12_2D, CTRL, 26), + this->cover.status ? + FEATURE_ENABLE_ENABLE_CLOSED_COVER_DETECTION_MASK : 0, + FEATURE_ENABLE_ENABLE_CLOSED_COVER_DETECTION_MASK); + break; + case SYN_CHIP_3500: + /* F51_CUSTOM_CTRL05.00: Cover */ + rc = clearpad_put( + SYNF(this, F51_CUSTOM, CTRL, + this->reg_offset.f51_ctrl05), + this->cover.status ? + COVER_ENABLE_MASK | COVER_REPORT_FINGER_MASK : 0x00); + break; + default: + LOGE(this, "not supported chip id (0x%02x)\n", this->chip_id); + rc = -EINVAL; + break; + } + if (rc) + goto end; + + /* Set glove finger register in touch ic */ + if (this->cover.status) { + rc = clearpad_set_glove_finger_reg(this, true); + } else { + rc = clearpad_set_glove_finger_reg(this, this->glove.enabled); + } + if (rc) + goto end; + + switch (this->chip_id) { + case SYN_CHIP_3330: + case SYN_CHIP_332U: + /* Report Glove As Finger setting is not needed */ + break; + case SYN_CHIP_3500: + /* F12_2D_CTRL23_02: Report As Finger */ + rc = clearpad_get_block(SYNA(this, F12_2D, CTRL, 23), buf, + buf_size); + if (rc) + goto end; + + BIT_SET(buf[F12_2D_CTRL_REPORT_AS_FINGER], + REPORT_AS_FINGER_GLOVED_FINGER, + this->cover.status ? 1 : 0); + rc = clearpad_put_block(SYNA(this, F12_2D, CTRL, 23), buf, + buf_size); + if (rc) + goto end; + break; + default: + LOGE(this, "not supported chip id (0x%02x)\n", this->chip_id); + break; + } + + /* F54_ANALOG_CMD00: Analog Command */ + rc = clearpad_put( + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + ANALOG_COMMAND_FORCE_UPDATE_MASK); + if (rc) + goto end; + + rc = clearpad_set_doze_holdoff(this); + if (rc) + LOGE(this, "failed to set Doze Holdoff\n"); +end: + if (rc) + LOGE(this, "failed to set cover status"); + + return rc; +} + +static int clearpad_set_cover_window(struct clearpad_t *this) +{ + int rc; + u8 block_buf[8]; + + if (this->chip_id == SYN_CHIP_3330 || + this->chip_id == SYN_CHIP_332U) { + /* Cover window size register F12_2D_CTRL25 */ + if (!clearpad_is_valid_function(this, SYN_F12_2D)) { + LOGE(this, "F12_2D is required to set cover window"); + rc = -EPERM; + goto end; + } + + block_buf[0] = this->cover.win_left; + block_buf[1] = this->cover.win_left >> 8; + block_buf[2] = this->cover.win_right; + block_buf[3] = this->cover.win_right >> 8; + block_buf[4] = this->cover.win_top; + block_buf[5] = this->cover.win_top >> 8; + block_buf[6] = this->cover.win_bottom; + block_buf[7] = this->cover.win_bottom >> 8; + + /* F12_2D_CTRL25: Closed Xmin/Xmax/Ymin/Ymax */ + rc = clearpad_put_block(SYNA(this, F12_2D, CTRL, 25), + block_buf, 8); + if (rc) + goto end; + } else { + /* Cover window size register F51_CUSTOM_CTRL05 */ + if (!clearpad_is_valid_function(this, SYN_F51_CUSTOM)) { + LOGE(this, "F51 is required to set cover window"); + rc = -EPERM; + goto end; + } + + block_buf[0] = this->cover.win_left; + block_buf[1] = this->cover.win_left >> 8; + block_buf[2] = this->cover.win_top; + block_buf[3] = this->cover.win_top >> 8; + block_buf[4] = this->cover.win_right; + block_buf[5] = this->cover.win_right >> 8; + block_buf[6] = this->cover.win_bottom; + block_buf[7] = this->cover.win_bottom >> 8; + + /* F51_CUSTOM_CTRL05.01: Cover Left/Top/Right/Bottom */ + rc = clearpad_put_block( + SYNF(this, F51_CUSTOM, CTRL, + this->reg_offset.f51_ctrl05 + + SYN_COVER_RECTANGLE_OFFSET), + block_buf, 8); + if (rc) + goto end; + } + + rc = clearpad_set_cover_status(this); +end: + if (rc) + LOGE(this, "failed to set cover window"); + return rc; +} + +/* + * Stamina (Report rate) + */ + +/* need LOCK(&this->lock) */ +static int clearpad_change_report_rate(struct clearpad_t *this) +{ + int rc = 0; + bool enable = false, report_status = false; + u8 buf; + + if (!this) { + LOGE(this, "failed get this data\n"); + rc = -EINVAL; + goto exit; + } + + if (!this->stamina.change_reportrate.supported) + goto exit; + + if (this->stamina.change_reportrate.mode > 0) + enable = true; + else + enable = false; + + switch (this->chip_id) { + case SYN_CHIP_3330: + case SYN_CHIP_332U: + rc = clearpad_get(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), &buf); + if (rc) { + LOGE(this, "failed to get status\n"); + rc = -EINVAL; + goto exit; + } + if (BIT_GET(buf, DEVICE_CONTROL_REPORT_RATE)) + report_status = true; + + if (enable == report_status) { + LOGI(this, "report rate is already %s\n", + this->stamina.enabled ? "enabled" : "disabled"); + goto exit; + } + + rc = clearpad_put_bit( + SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), + enable ? DEVICE_CONTROL_REPORT_RATE_MASK : 0, + DEVICE_CONTROL_REPORT_RATE_MASK); + if (rc) { + LOGE(this, "failed to set report rate\n"); + goto exit; + } + LOGI(this, "report rate %s\n", + enable ? "enable" : "disable"); + + clearpad_set_delay(SYN_WAIT_TIME_AFTER_CHANGE_REPORTRATE); + + /* F54_ANALOG_CMD00: Analog Command */ + rc = clearpad_put(SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + ANALOG_COMMAND_FORCE_UPDATE_MASK); + if (rc) { + LOGE(this, "failed to set force update\n"); + goto exit; + } + + break; + case SYN_CHIP_3500: + /* F51_CUSTOM_CTRL30.06[1:0]: External Report Rate Selection */ + rc = clearpad_put( + SYNF(this, F51_CUSTOM, CTRL, + this->reg_offset.f51_ctrl30 + + SYN_EXTERNAL_REPORT_RATE_OFFSET), + this->stamina.change_reportrate.mode); + if (rc) { + LOGE(this, "failed to set change report rate\n"); + goto exit; + } + + break; + default: + LOGE(this, "not supported on chip id 0x0%2x\n", this->chip_id); + goto exit; + } + +exit: + return rc; +} + +/* + * Stamina + */ + +/* need LOCK(&this->lock) */ +static int clearpad_set_stamina_mode(struct clearpad_t *this) +{ + int rc = 0; + + if (!this->stamina.supported) + goto end; + + rc = clearpad_change_report_rate(this); + if (rc) + LOGE(this, "failed to change report rate\n"); + +end: + return rc; +} + +/* + * Wakeup gesture (EW) + */ + +/* need LOCK(&this->lock) */ +static int clearpad_enable_wakeup_gesture(struct clearpad_t *this) +{ + u8 buf[F12_2D_CTRL_RPT_REG_MAX]; + int rc = 0; + + if (!clearpad_is_valid_function(this, SYN_F12_2D)) { + LOGE(this, "F12 is required to set wakeup gesture\n"); + rc = -EPERM; + goto end; + } + + if (this->chip_id == SYN_CHIP_3330 && + !clearpad_is_valid_function(this, SYN_F54_ANALOG)) { + LOGE(this, "F54 is required to set wakeup gesture\n"); + rc = -EPERM; + goto end; + } + + /* F01_RMI_CTRL00: Device Control */ + rc = clearpad_put_bit( + SYNF(this, F01_RMI, CTRL, this->reg_offset.f01_ctrl00), + DEVICE_CONTROL_CONFIGURED_MASK, + DEVICE_CONTROL_CONFIGURED_MASK); + if (rc) { + LOGE(this, "failed to set device configured bit\n"); + goto end; + } + clearpad_set_delay(SYN_WAIT_TIME_AFTER_REGISTER_ACCESS); + + if (this->chip_id == SYN_CHIP_3330 && + this->wakeup_gesture.use_workaround_for_felica) { + /* F12_2D_CTRL33_00: Multi-Finger Moisture General */ + rc = clearpad_get_block(SYNA(this, F12_2D, CTRL, 33), + buf, 1); + if (rc) { + LOGE(this, "failed to read enable multifinger " + "moisture register\n"); + goto end; + } + BIT_SET(buf[0], ENABLE_MULTIFINGER_MOISTURE, 0); + rc = clearpad_put_block(SYNA(this, F12_2D, CTRL, 33), + buf, 1); + if (rc) { + LOGE(this, "failed to set enable multifinger " + "moisture bit\n"); + goto end; + } + + /* F54_ANALOG_CTRL113_00: General Control */ + rc = clearpad_put_bit(SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl113), + DISABLE_HYBRID_BASELINE_MASK, + DISABLE_HYBRID_BASELINE_MASK); + if (rc) { + LOGE(this, "failed to set disable hybrid baseline\n"); + goto end; + } + /* F54_ANALOG_CTRL109_00: General Control */ + rc = clearpad_put(SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl109), + BASELINE_CORRECTION_MODE_MASK); + if (rc) { + LOGE(this, "failed to set baseline correction mode\n"); + goto end; + } + /* F54_ANALOG_CTRL147_00: Disable Hybrid CBC Auto Correction */ + rc = clearpad_put_bit(SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl147), + DISABLE_HYBRID_CBC_AUTO_CORRECTION_MASK, + DISABLE_HYBRID_CBC_AUTO_CORRECTION_MASK); + if (rc) { + LOGE(this, "failed to set Disable Hybrid CBC Auto " + "Correction\n"); + goto end; + } + /* F54_ANALOG_CTRL214_00: General Control */ + rc = clearpad_put_bit(SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl214), 0, + ENABLE_HYBRID_CHARGER_NOISE_MITIGATION_MASK); + if (rc) { + LOGE(this, "failed to set enable hybrid charger noise " + "mitigation\n"); + goto end; + } + /* F54_ANALOG_CMD00: Analog Command */ + rc = clearpad_put( + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + ANALOG_COMMAND_FORCE_UPDATE_MASK); + if (rc) { + LOGE(this, "failed to set force update\n"); + goto end; + } + clearpad_set_delay(50); + } + /* F12_2D_CTRL20_01: Report Flags */ + rc = clearpad_get_block(SYNA(this, F12_2D, CTRL, 20), + buf, F12_2D_CTRL_RPT_REG_MAX); + if (rc) { + LOGE(this, "failed to read control report register\n"); + goto end; + } + BIT_SET(buf[F12_2D_CTRL_RPT_FLAG], + REPORT_FLAGS_REPORT_WAKEUP_GESTURE_ONLY, 1); + rc = clearpad_put_block(SYNA(this, F12_2D, CTRL, 20), + buf, F12_2D_CTRL_RPT_REG_MAX); + if (rc) { + LOGE(this, "failed to enable wakeup gesture\n"); + goto end; + } + + /* F12_2D_CTRL27_00: Wakeup Gesture Enable */ + rc = clearpad_put(SYNA(this, F12_2D, CTRL, 27), + WAKEUP_GESTURE_ENABLE_DOUBLE_TAP_MASK); + if (rc) { + LOGE(this, "failed to enable double tap gesture\n"); + goto end; + } +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_disable_wakeup_gesture(struct clearpad_t *this) +{ + u8 buf[F12_2D_CTRL_RPT_REG_MAX]; + int rc = 0; + + if (!clearpad_is_valid_function(this, SYN_F12_2D)) { + LOGE(this, "F12 is required to set wakeup gesture\n"); + rc = -EPERM; + goto end; + } + + switch (this->chip_id) { + case SYN_CHIP_3330: + case SYN_CHIP_332U: + LOGD(this, "already disabled wakeup gesture by HW reset\n"); + break; + case SYN_CHIP_3500: + /* F12_2D_CTRL27_00: Wakeup Gesture Enable */ + rc = clearpad_put(SYNA(this, F12_2D, CTRL, 27), 0); + if (rc) { + LOGE(this, "failed to disable double tap gesture\n"); + goto end; + } + + /* F12_2D_CTRL20_01: Report Flags */ + rc = clearpad_get_block(SYNA(this, F12_2D, CTRL, 20), + buf, F12_2D_CTRL_RPT_REG_MAX); + if (rc) { + LOGE(this, "failed to read control report register\n"); + goto end; + } + BIT_CLEAR(buf[F12_2D_CTRL_RPT_FLAG], + REPORT_FLAGS_REPORT_WAKEUP_GESTURE_ONLY); + rc = clearpad_put_block(SYNA(this, F12_2D, CTRL, 20), + buf, F12_2D_CTRL_RPT_REG_MAX); + if (rc) { + LOGE(this, "failed to disable report gesture\n"); + goto end; + } + + /* F54_ANALOG_CMD00: Analog Command */ + rc = clearpad_put( + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + ANALOG_COMMAND_FORCE_CALIBRATION_MASK); + if (rc) + LOGE(this, "failed to force calibrate\n"); + break; + default: + LOGE(this, "not supported on chip id 0x0%2x\n", this->chip_id); + break; + } +end: + return rc; +} + +static int clearpad_set_feature_settings(struct clearpad_t *this) +{ + int rc; + + rc = clearpad_set_charger(this); + if (rc) + goto end; + rc = clearpad_set_pen(this); + if (rc) + goto end; + rc = clearpad_set_glove_mode(this, this->glove.enabled); + if (rc) + goto end; + if (this->cover.enabled) + rc = clearpad_set_cover_window(this); + if (rc) + goto end; + if (this->stamina.enabled) + rc = clearpad_set_stamina_mode(this); + if (rc) + goto end; + rc = clearpad_set_doze_holdoff(this); +end: + return rc; +} + +static int clearpad_gen_offsets(u8 desc, u8 offset_from, u8 reg_array[], + int reg_from, int array_size) +{ + const u8 unused_offset = 0xFF; + int offset = offset_from; + int bit, reg = reg_from; + + for (bit = 0; bit < 8 && reg < array_size; bit++) + reg_array[reg++] = desc & (1 << bit) ? offset++ : unused_offset; + + if (reg >= SYN_MAX_CTRL_VALUE) { + WARN_ON(reg >= SYN_MAX_CTRL_VALUE); + offset = -1; + }; + + return offset; +} + +static int clearpad_query_regs(struct clearpad_t *this, + enum clearpad_function_e func, + u8 query, u8 reg_array[], int reg_array_size) +{ + /* register presence descriptors: maximum 32 bytes */ + const int max_size_presence = 32; + /* size of register structure: 1 or 3 bytes */ + const int max_size_bytes = 3; + + u8 buffer[max_size_bytes + max_size_presence]; + u8 size_presence; + int offset = 0; + int size_num_bytes; + int rc, i; + + rc = clearpad_get(SYNI(this, func, SYN_TYPE_QUERY, query), + &size_presence); + if (rc) + goto end; + + BUG_ON(size_presence > max_size_presence); + + /* The size of the control register structure is currently unused, + * but we need to find out how many bytes are allocated for it. + */ + rc = clearpad_get(SYNI(this, func, SYN_TYPE_QUERY, query + 1), buffer); + if (rc) + goto end; + + size_num_bytes = buffer[0] == 0 ? max_size_bytes : 1; + + rc = clearpad_get_block(SYNI(this, func, SYN_TYPE_QUERY, query + 1), + buffer, size_num_bytes + size_presence); + if (rc) + goto end; + + for (i = 0; i < size_presence; i++) { + offset = clearpad_gen_offsets(buffer[i + size_num_bytes], + offset, reg_array, i * 8, reg_array_size); + if (offset < 0) { + HWLOGW(this, "register id is out of range\n"); + goto end; + } + } +end: + return rc; +} + +static void clearpad_log_offsets(struct clearpad_t *this, const char *header, + enum clearpad_function_e func, + u8 reg_array[], int reg_array_size) +{ + int i; + + LOGD(this, "%s(%d)\n", header, func); + for (i = 0; i < reg_array_size; i++) + LOGD(this, "[%.2d]=0x%02hX\n", i, (u16)reg_array[i]); +} + +static int clearpad_init_reg_offsets(struct clearpad_t *this, + enum clearpad_function_e func) +{ + const u8 query_query_register_presence = 0x01; + const u8 query_ctrl_register_presence = 0x04; + const u8 query_data_register_presence = 0x07; + u8 query_desc; + int rc; + + rc = clearpad_get(SYNI(this, func, SYN_TYPE_QUERY, 0x00), &query_desc); + if (rc) + goto end; + + if (!(BIT_GET(query_desc, GENERAL_HAS_REGISTER_DESCRIPTOR))) { + LOGE(this, "register descriptors not supported!\n"); + rc = -EINVAL; + goto end; + } + + rc = clearpad_query_regs(this, func, query_query_register_presence, + this->pdt[func].offset[SYN_TYPE_QUERY], + ARRAY_SIZE(this->pdt[func].offset[SYN_TYPE_QUERY])); + if (rc) + goto end; + + clearpad_log_offsets(this, "query offsets", func, + this->pdt[func].offset[SYN_TYPE_QUERY], + ARRAY_SIZE(this->pdt[func].offset[SYN_TYPE_QUERY])); + + rc = clearpad_query_regs(this, func, query_ctrl_register_presence, + this->pdt[func].offset[SYN_TYPE_CTRL], + ARRAY_SIZE(this->pdt[func].offset[SYN_TYPE_CTRL])); + if (rc) + goto end; + + clearpad_log_offsets(this, "control offsets", func, + this->pdt[func].offset[SYN_TYPE_CTRL], + ARRAY_SIZE(this->pdt[func].offset[SYN_TYPE_CTRL])); + + rc = clearpad_query_regs(this, func, query_data_register_presence, + this->pdt[func].offset[SYN_TYPE_DATA], + ARRAY_SIZE(this->pdt[func].offset[SYN_TYPE_DATA])); + + clearpad_log_offsets(this, "data offsets", func, + this->pdt[func].offset[SYN_TYPE_DATA], + ARRAY_SIZE(this->pdt[func].offset[SYN_TYPE_DATA])); +end: + return rc; +} + +static int clearpad_prepare_f12_2d(struct clearpad_t *this) +{ + int rc; + int i; + u8 buf[4]; + enum registers { + REG_X_LSB, + REG_X_MSB, + REG_Y_LSB, + REG_Y_MSB, + }; + + rc = clearpad_init_reg_offsets(this, SYN_F12_2D); + if (rc) + goto end; + + /* F12_2D_CTRL08_[00-03]: Maximum XY Coordinate */ + rc = clearpad_get_block(SYNA(this, F12_2D, CTRL, 8), buf, sizeof(buf)); + if (rc) + goto end; + this->extents.x_max = (buf[REG_X_LSB] | (buf[REG_X_MSB] << 8)); + this->extents.y_max = (buf[REG_Y_LSB] | (buf[REG_Y_MSB] << 8)); + + WARN_ON(this->extents.preset_x_max != this->extents.x_max); + WARN_ON(this->extents.preset_y_max != this->extents.y_max); + + /* F12_2D_CTRL23_01: Max Number Of Reported Objects */ + rc = clearpad_get_block(SYNA(this, F12_2D, CTRL, 23), buf, 2); + if (rc) + goto end; + this->extents.n_fingers = buf[F12_2D_CTRL_MAX_OBJ_REPORT]; + + /* F12_2D_CTRL28: Data Reporting Enable Mask */ + rc = clearpad_get(SYNA(this, F12_2D, CTRL, 28), buf); + if (rc) + goto end; + + this->extents.n_bytes_per_object = 0; + + for (i = 0; i < BITS_PER_BYTE; i++) + this->extents.n_bytes_per_object += (buf[0] & BIT(i)) >> i; + + LOGI(this, "x_max=%d, y_max=%d, n_fingers=%d, n_bytes_per_object=%d\n", + this->extents.x_max, this->extents.y_max, + this->extents.n_fingers, + this->extents.n_bytes_per_object); + + rc = clearpad_set_feature_settings(this); + +end: + return rc; +} + +static void clearpad_firmware_reset(struct clearpad_t *this) +{ + this->flash.data.pos = 0; + this->flash.config.pos = 0; + if (this->flash.fw) { + release_firmware(this->flash.fw); + this->flash.fw = NULL; + } + HWLOGI(this, "firmware image has been reset\n"); +} + +static int clearpad_initialize(struct clearpad_t *this) +{ + int rc; + u8 fw_info[SYN_DEVICE_INFO_SIZE], bl_ver[SYN_DEVICE_BL_INFO_SIZE]; + u8 device_status, fw_status; + struct clearpad_device_info_t *info = &this->device_info; + u8 product_id[HEADER_PRODUCT_ID_SIZE]; + + LOGI(this, "initialize device\n"); + + /* read device product id */ + /* F01_RMI_QUERY11: Product ID Query */ + rc = clearpad_get_block(SYNF(this, F01_RMI, QUERY, + this->reg_offset.f01_query11), + product_id, HEADER_PRODUCT_ID_SIZE); + if (rc) + goto end; + memcpy(info->product_id, product_id, HEADER_PRODUCT_ID_SIZE); + + clearpad_update_chip_id(this); + + clearpad_set_is_sol(this); + + /* read device status */ + /* F01_RMI_DATA00: Device Status */ + rc = clearpad_get(SYNF(this, F01_RMI, DATA, + this->reg_offset.f01_data00), + &device_status); + if (rc) + goto end; + + LOGI(this, "device status 0x%02x\n", device_status); + + if (this->is_sol) { + /* F34_FLASH_QUERY00: Bootloader Revision */ + rc = clearpad_get_block(SYNF(this, F34_FLASH, QUERY, + this->reg_offset.f34_query00), + bl_ver, SYN_DEVICE_BL_INFO_SIZE); + if (rc) + goto end; + + /* Flash memory management, Version 1 */ + /* Bootloader Revision is stored as character */ + LOGI(this, "bl[0]:%c\n", bl_ver[0]); + LOGI(this, "bl[1]:%c\n", bl_ver[1]); + if (bl_ver[1] >= 0x30 && bl_ver[1] <= 0x39) { + /* change character to decimal */ + bl_ver[1] -= 0x30; + bl_ver[0] = 0x00; /* minor value is 0 */ + } + LOGI(this, "bootloader revision %d.%03d\n", bl_ver[1], bl_ver[0]); + } else { + /* F34_FLASH_QUERY01: Bootloader Revision */ + rc = clearpad_get_block(SYNF(this, F34_FLASH, QUERY, + this->reg_offset.f34_query01), + bl_ver, SYN_DEVICE_BL_INFO_SIZE); + if (rc) + goto end; + + /* Flash memory management, Version 2 */ + /* Bootloader Revision is stored as decimal */ + LOGI(this, "bootloader revision %d.%03d\n", bl_ver[1], bl_ver[0]); + } + + switch (BIT_GET(device_status, DEVICE_STATUS_CODE)) { + case DEVICE_STATUS_CODE_CONFIGURATION_CRC_FAILURE: + case DEVICE_STATUS_CODE_FIRMWARE_CRC_FAILURE: + case DEVICE_STATUS_CODE_CRC_IN_PROGRESS: + /* force firmware recovery */ + memset(fw_info, 0, sizeof(fw_info)); + break; + default: + if (bl_ver[1] >= clearpad_bootloader_version_dec[BV7]) { + /* F34_FLASH_DATA00: Status */ + rc = clearpad_get(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data00), + &fw_status); + if (rc) + goto end; + + LOGI(this, "FW status 0x%02x\n", fw_status); + + switch (BIT_GET(fw_status, STATUS_FLASH_STATUS)) { + case STATUS_FLASH_STATUS_BAD_PARTITION_TABLE: + case STATUS_FLASH_STATUS_CHECKSUM_FAILED: + /* force firmware recovery */ + memset(fw_info, 0, sizeof(fw_info)); + break; + default: + break; + } + rc = clearpad_get_block( + SYNF(this, F34_FLASH, CTRL, + this->reg_offset.f34_ctrl00), fw_info, + FLASH_READ_FIRMWARE_INFO_SIZE_BL7X); + if (rc) + goto end; + + info->customer_family = fw_info[0]; + info->firmware_revision_major = fw_info[1]; + info->firmware_revision_minor = fw_info[2]; + info->firmware_revision_extra = fw_info[3]; + info->analog_id = fw_info[4]; + info->boot_loader_version_minor = bl_ver[0]; + info->boot_loader_version_major = bl_ver[1]; + } else if (bl_ver[1] >= clearpad_bootloader_version_dec[BV6]) { + rc = clearpad_get_block(SYNF(this, F34_FLASH, CTRL, + this->reg_offset.f34_ctrl00), + fw_info, FLASH_READ_FIRMWARE_INFO_SIZE_BL6X); + if (rc) + goto end; + + info->customer_family = fw_info[0]; + info->firmware_revision_major = fw_info[1]; + info->firmware_revision_minor = fw_info[2]; + info->firmware_revision_extra = fw_info[3]; + info->boot_loader_version_minor = bl_ver[0]; + info->boot_loader_version_major = bl_ver[1]; + } + break; + } + + /* overwrite default settings with actual chip settings */ + clearpad_touch_config_dt_for_chip_id(this, this->chip_id); + + if (this->state != SYN_STATE_RUNNING) { + LOGI(this, "device mid %d, prop %d, family 0x%02x, " + "rev 0x%02x.%02x, extra 0x%02x, aid 0x%02x\n", + info->manufacturer_id, info->product_properties, + info->customer_family, info->firmware_revision_major, + info->firmware_revision_minor, + info->firmware_revision_extra, + info->analog_id); + LOGI(this, "product id '%s'\n", + clearpad_s(info->product_id, HEADER_PRODUCT_ID_SIZE)); + } + + if (clearpad_is_valid_function(this, SYN_F12_2D)) { + rc = clearpad_prepare_f12_2d(this); + if (rc) + goto end; + } + + /* set device configured bit */ + /* F01_RMI_CTRL00: Device Control */ + rc = clearpad_put_bit(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), + DEVICE_CONTROL_CONFIGURED_MASK, + DEVICE_CONTROL_CONFIGURED_MASK); + if (rc) + goto end; + + clearpad_set_delay(SYN_WAIT_TIME_AFTER_REGISTER_ACCESS); + + snprintf(this->result_info, sizeof(this->result_info), + "%s, family 0x%02x, fw rev 0x%02x.%02x, extra 0x%02x, (%s)\n", + clearpad_s(this->device_info.product_id, + HEADER_PRODUCT_ID_SIZE), + this->device_info.customer_family, + this->device_info.firmware_revision_major, + this->device_info.firmware_revision_minor, + this->device_info.firmware_revision_extra, + this->flash_requested ? "fw updated" : "no fw update"); + this->flash_requested = false; + + /* notify end of task */ + LOGI(this, "result: %s", this->result_info); +end: + /* inform running state */ + this->state = SYN_STATE_RUNNING; + return rc; +} + +/* + * @return 1 : initialized + * 0 : not initialized since interrupt.count != 0 + * negative value : error + * need LOCK(&this->lock) + */ +static int clearpad_initialize_if_first_event(struct clearpad_t *this, + u8 *interrupt_status, + u8 *device_status) +{ + struct timespec ts; + int rc = 0; + int retry; + + if (this->interrupt.count != 0) + goto read_interrupt; + + get_monotonic_boottime(&ts); + HWLOGI(this, "read first event (power=%s active=%s) @ %ld.%06ld\n", + touchctrl_is_touch_powered(this) ? "OK" : "NG", + this->dev_active ? "true" : "false", + ts.tv_sec, ts.tv_nsec); + + for (retry = 0; retry < SYN_RETRY_NUM; retry++) { + clearpad_set_delay(this->reset.delay_for_powerup_ms); + rc = clearpad_set_page(this, 0); + if (!rc) + goto read_pdt; + } + HWLOGE(this, "failed to set page 0\n"); + goto err_in_set_page; + +read_pdt: + rc = clearpad_read_pdt(this); + if (rc) { + HWLOGE(this, "failed to read pdt\n"); + goto err_in_read_pdt; + } + +read_interrupt: + /* F01_RMI_DATA01: Interrupt Status */ + rc = clearpad_get(SYNF(this, F01_RMI, DATA, + this->reg_offset.f01_data01), interrupt_status); + if (rc) { + HWLOGE(this, "failed to read interrupt status\n"); + goto end; + } + /* F01_RMI_DATA00: Device Status */ + rc = clearpad_get(SYNF(this, F01_RMI, DATA, + this->reg_offset.f01_data00), device_status); + if (rc) { + HWLOGE(this, "failed to read device status\n"); + goto end; + } + if (this->interrupt.count != 0) + goto end; + + rc = clearpad_initialize(this); + if (rc) { + HWLOGE(this, "failed to initialize (rc=%d)\n", rc); + goto end; + } + rc = 1; +end: + return rc; + +err_in_set_page: +err_in_read_pdt: + /* this workaround will be replaced by HW reset */ + HWLOGE(this, "retry reading interrupt status as workaround\n"); + /* F01_RMI_DATA01: Interrupt Status */ + rc = clearpad_get(SYNF(this, F01_RMI, DATA, + this->reg_offset.f01_data01), interrupt_status); + if (rc) + HWLOGE(this, "failed to read interrupt status\n"); + return -EIO; +} + +/* + * @return 1 : initialized + * 0 : not initialized since interrupt.count != 0 + * negative value : error + * need LOCK(&this->lock) + */ +static int clearpad_handle_if_first_event(struct clearpad_t *this) +{ + int rc = 0; + + if (this->interrupt.count != 0) + goto end; + + get_monotonic_boottime(&this->interrupt.handle_first_event_ts); + + HWLOGI(this, "first event (power=%s active=%s) @ %ld.%06ld\n", + touchctrl_is_touch_powered(this) ? "OK" : "NG", + this->dev_active ? "true" : "false", + this->interrupt.handle_first_event_ts.tv_sec, + this->interrupt.handle_first_event_ts.tv_nsec); + + rc = clearpad_process_irq(this); + if (rc) + HWLOGE(this, "failed to read interrupt, " + "but ignore (rc=%d)\n", rc); + + if (!this->post_probe.done) + goto end; + + if (this->force_sleep == FSMODE_ONESHOT) { + LOGI(this, "clear force sleep mode\n"); + this->force_sleep = FSMODE_OFF; + } + if (this->force_sleep != FSMODE_OFF) { + HWLOGI(this, "force sleep mode\n"); + if (this->dev_active) { + rc = clearpad_set_suspend_mode(this); + if (rc) + HWLOGE(this, "failed to force sleep mode\n"); + } + } else if (!this->dev_active) { + rc = clearpad_set_resume_mode(this); + if (rc) + HWLOGE(this, "failed to resume (rc=%d)\n", rc); + } + rc = rc < 0 ? rc : 1; +end: + return rc; +} + +void clearpad_parse_descriptor(struct clearpad_t *this, u32 container_addr) +{ + struct descriptor_t desc; + struct clearpad_flash_t *f = &this->flash; + const u8 *data = this->flash.fw->data; + u8 *cc_content_addr; + + desc.container_id = (u16)le32_to_cpu(*(u32 *) + (data + container_addr + CON_ID_OFFSET)); + LOGD(this, "container_addr=%d", container_addr); + desc.content_len = le32_to_cpu(*(u32 *)(data + + container_addr + CON_CONTENT_LENGTH_OFFSET)); + desc.content_start_addr = le32_to_cpu(*(u32 *) + (data + container_addr + CON_CONTENT_ADDRESS_OFFSET)); + LOGD(this, + "container_id=%d, desc.content_len=%d, desc.content_start_addr=%d\n", + desc.container_id, desc.content_len, desc.content_start_addr); + + cc_content_addr = (u8 *)(data + desc.content_start_addr); + /* Set up block info */ + switch (desc.container_id) { + case CID_CORE_CODE_CONTAINER: + f->data.length = desc.content_len; + f->data.data = cc_content_addr; + HWLOGD(this, "core code: data (length %u)\n", f->data.length); + break; + case CID_CORE_CONFIGURATION_CONTAINER: + f->config.length = desc.content_len; + f->config.data = cc_content_addr; + f->customer_family = *cc_content_addr + + CONFIG_CUSTOMER_FAMILY_OFFSET; + f->firmware_revision_major = + *(cc_content_addr + CONFIG_FIRMWARE_REVISION_MAJOR_OFFSET); + f->firmware_revision_minor = + *(cc_content_addr + CONFIG_FIRMWARE_REVISION_MINOR_OFFSET); + f->firmware_revision_extra = + *(cc_content_addr + CONFIG_FIRMWARE_REVISION_EXTRA_OFFSET); + HWLOGD(this, + "core config: family 0x%02x, rev 0x%02x.%02x.0x%02x\n", + f->customer_family, f->firmware_revision_major, + f->firmware_revision_minor, f->firmware_revision_extra); + break; + default: + HWLOGD(this, "core(container id %d)\n", desc.container_id); + break; + } +} + +void clearpad_parse_container(struct clearpad_t *this) +{ + int i, j = 0; + u8 cont_count; + u32 offset, top_container_addr, container_addr, cont_len; + const u8 *data = this->flash.fw->data; + + HWLOGI(this, "start parse\n"); + offset = le32_to_cpu(*(u32 *)(data + CON_TOP_START_ADDRESS_OFFSET)); + LOGD(this, "offset=%d\n", offset); + + cont_len = le32_to_cpu(*(u32 *)(data + offset + + CON_CONTENT_LENGTH_OFFSET)); + cont_count = cont_len / CON_START_ADDRESS_SIZE; + top_container_addr = le32_to_cpu(*(u32 *)(data + offset + + CON_CONTENT_ADDRESS_OFFSET)); + LOGD(this, "cont_len=%d, top_container_addr=%d\n", + cont_len, top_container_addr); + + for (i = 0; i < cont_count; i++) { + container_addr = + le32_to_cpu(*(u32 *)(data + top_container_addr + j)); + j += CON_START_ADDRESS_SIZE; + LOGD(this, "container_addr=%d, i=%d, j=%d\n", + container_addr, i, j); + clearpad_parse_descriptor(this, container_addr); + } +} + +static void clearpad_parse_firmware(struct clearpad_t *this) +{ + const u8 *data; + struct clearpad_flash_t *f = &this->flash; + + data = this->flash.fw->data; + LOGI(this, "data:%p\n", data); + + /* Set up data block info */ + f->data.length = le32_to_cpu(*(u32 *)(data + 8)); + f->data.blocks = (f->data.length / 16) + !!(f->data.length % 16); + f->data.data = data + HEADER_SIZE; + f->data.pos = 0; + LOGI(this, "DATA: length=%x blocks=%x data=%p\n", + f->data.length, f->data.blocks, f->data.data); + + /* Set up configuration block info */ + f->config.length = le32_to_cpu(*(u32 *)(data + 12)); + f->config.blocks = (f->config.length / 16) + !!(f->config.length % 16); + f->config.data = data + HEADER_SIZE + f->data.length; + f->config.pos = 0; + LOGI(this, "CONFIG: length=%x blocks=%x data=%p\n", + f->config.length, f->config.blocks, f->config.data); + + /* family Rev major minor extra info */ + f->customer_family = + *(data + f->data.length + HEADER_SIZE + CONFIG_CUSTOMER_FAMILY_OFFSET); + f->firmware_revision_major = + *(data + f->data.length + HEADER_SIZE + CONFIG_FIRMWARE_REVISION_MAJOR_OFFSET); + f->firmware_revision_minor = + *(data + f->data.length + HEADER_SIZE + CONFIG_FIRMWARE_REVISION_MINOR_OFFSET); + f->firmware_revision_extra = + *(data + f->data.length + HEADER_SIZE + CONFIG_FIRMWARE_REVISION_EXTRA_OFFSET); + LOGI(this, + "core config: family 0x%02x, rev 0x%02x.%02x.0x%02x\n", + f->customer_family, f->firmware_revision_major, + f->firmware_revision_minor, f->firmware_revision_extra); + +} + +static ssize_t clearpad_get_firmware(struct clearpad_t *this, char *filename) +{ + int rc; + struct clearpad_flash_t *f = &this->flash; + + rc = request_firmware(&f->fw, filename, this->bdata->dev); + if (rc || !f->fw) { + HWLOGE(this, "fw request failed (rc=%d, fw=%p, name=%s)\n", + rc, f->fw, filename); + rc = -EINVAL; + goto end; + } + + f->format_version = f->fw->data[HEADER_VERSION_OFFSET]; + if (f->format_version >= BV7) { + clearpad_parse_container(this); + } else if (f->format_version >= BV6) { + clearpad_parse_firmware(this); + } else { + HWLOGE(this, "bootloader version not supported\n"); + rc = -ENODEV; + goto end; + } + + HWLOGD(this, "DATA: length=%d blocks=%d\n", + f->data.length, f->data.blocks); + HWLOGD(this, "CONFIG: length=%d blocks=%d\n", + f->config.length, f->config.blocks); + HWLOGI(this, "firmware image size=%zu\n", this->flash.fw->size); +end: + return rc; +} + +static int clearpad_get_pca_module_id(struct clearpad_t *this) +{ + u8 pca_block_data[SYN_PCA_BLOCK_SIZE]; + int i; + int rc; + + for (i = SYN_PCA_BLOCK_NUMBER_MAX; i >= 0; i--) { + rc = clearpad_read_pca_block(this, i, pca_block_data); + if (rc) { + HWLOGE(this, "failed to read pca\n"); + rc = -EIO; + goto end; + } + if (pca_block_data[PCA_DATA] == PCA_FW_INFO && + pca_block_data[PCA_IC] == SYN_CLEARPAD_VENDOR) { + rc = pca_block_data[PCA_MODULE]; + HWLOGI(this, "found module id 0x%02x in pca\n", rc); + goto end; + } + } + HWLOGI(this, "no module id in pca data:%x ic:%x chip:%x module:%x\n", + pca_block_data[PCA_DATA], pca_block_data[PCA_IC], + pca_block_data[PCA_CHIP], pca_block_data[PCA_MODULE]); + rc = -EINVAL; +end: + return rc; +} + +static int clearpad_get_pca_blank_block(struct clearpad_t *this) +{ + u8 pca_block_data[SYN_PCA_BLOCK_SIZE]; + int i; + int empty = -ENOMEM; + int rc; + + for (i = SYN_PCA_BLOCK_NUMBER_MAX; i >= 0; i--) { + rc = clearpad_read_pca_block(this, i, pca_block_data); + if (rc) { + HWLOGE(this, "failed to read pca\n"); + empty = rc; + goto end; + } + if (pca_block_data[PCA_DATA] == PCA_FW_INFO && + pca_block_data[PCA_IC] == SYN_CLEARPAD_VENDOR) + goto end; + if (pca_block_data[PCA_DATA] == PCA_NO_USE) + empty = i; + } +end: + return empty; +} + +/* need LOCK(&this->lock) */ +static int clearpad_judge_firmware_flash(struct clearpad_t *this, + unsigned int id, enum clearpad_flash_command_e flash_cmd) +{ + int pca_module_id; + int rc = 0; + int blank_block; + char filename[SYN_STRING_LENGTH] = ""; + u8 fw_info[SYN_PCA_BLOCK_SIZE] = {PCA_FW_INFO, SYN_CLEARPAD_VENDOR}; + + if (!this->device_info.customer_family) + HWLOGI(this, "device is broken\n"); + else + HWLOGI(this, "device is normal\n"); + + if (flash_cmd != SYN_FORCE_FLASH) { + pca_module_id = clearpad_get_pca_module_id(this); + if (pca_module_id < 0) + rc = pca_module_id; + if (pca_module_id == -EINVAL && + this->device_info.customer_family && this->chip_id) { + blank_block = clearpad_get_pca_blank_block(this); + if (blank_block < 0) { + HWLOGI(this, "no room to write\n"); + goto end_write_pca_block; + } + + fw_info[PCA_CHIP] = this->chip_id; + fw_info[PCA_MODULE] = this->device_info.customer_family; + rc = clearpad_write_pca_block(this, blank_block, + fw_info); + if (rc) { + HWLOGE(this, "failed to write pca\n"); + goto end_write_pca_block; + } + HWLOGI(this, "PCA written in block %d\n", blank_block); + } +end_write_pca_block: + if (pca_module_id > 0) { + id = pca_module_id; + HWLOGI(this, "pca value is valid\n"); + } else if (this->device_info.customer_family > 0) { + id = this->device_info.customer_family; + HWLOGI(this, "use device id since pca was invalid\n"); + } else { + HWLOGE(this, "failed to get valid id\n"); + } + } + + snprintf(filename, SYN_STRING_LENGTH, this->flash.firmware_name, id); + rc = clearpad_get_firmware(this, filename); + if (rc) { + HWLOGE(this, "failed to get firmware (module id 0x%02x)\n", id); + goto end; + } + + HWLOGI(this, "module id (device = 0x%02x, fw file = 0x%02x)\n", + id, this->flash.customer_family); + if (id != this->flash.customer_family) { + HWLOGW(this, "stop flashing, id is not matched with fw file\n"); + goto end; + } + + HWLOGI(this, "old firmware 0x%02x revision 0x%02x.%02x\n", + this->device_info.customer_family, + this->device_info.firmware_revision_major, + this->device_info.firmware_revision_minor); + HWLOGI(this, "new firmware 0x%02x revision 0x%02x.%02x\n", + this->flash.customer_family, + this->flash.firmware_revision_major, + this->flash.firmware_revision_minor); + + if (flash_cmd == SYN_FORCE_FLASH || + (this->device_info.customer_family != + this->flash.customer_family) || + (this->device_info.firmware_revision_major != + this->flash.firmware_revision_major) || + (this->device_info.firmware_revision_minor != + this->flash.firmware_revision_minor)) { + HWLOGI(this, "update of firmware is necessary\n"); + rc = 1; + } else { + HWLOGI(this, "update of firmware is unnecessary\n"); + } +end: + return rc; +} + +/* for Bootloader v6.0 */ +static int clearpad_flash_enable_bl_v6_0(struct clearpad_t *this) +{ + int rc; + u8 buf[SYN_DEVICE_BL_INFO_SIZE]; + + /* read bootloader id */ + rc = clearpad_get_block(SYNF(this, F34_FLASH, QUERY, + this->reg_offset.f34_query00), + buf, sizeof(buf)); + LOG_CHECK(this, "rc=%d\n", rc); + if (rc) + goto end; + + /* write bootloader id to block data */ + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data01), + buf, sizeof(buf)); + LOG_CHECK(this, "rc=%d\n", rc); + if (rc) + goto end; + + clearpad_set_delay(10); + + /* issue a flash program enable */ + this->flash.enter_bootloader_mode = true; + rc = clearpad_put(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data02), + FLASH_CONTROL_ENABLE_FLASH_PROGRAMMING); + LOG_CHECK(this, "rc=%d\n", rc); + if (rc) + goto end; + + this->state = SYN_STATE_FLASH_ENABLE; + clearpad_set_delay(100); + + clearpad_set_irq(this, true); + +end: + return rc; +} + +static int clearpad_flash_program_bl_v6_0(struct clearpad_t *this) +{ + struct clearpad_flash_t *flash = &this->flash; + int rc; + u8 buf[SYN_DEVICE_BL_INFO_SIZE]; + + /* make sure that we are in programming mode and there are no issues */ + rc = clearpad_get(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data03), buf); + if (rc) { + HWLOGE(this, "failed to get flash programming status\n"); + goto end; + } + if (!(BIT_GET(buf[0], STATUS_BL_MODE))) { + HWLOGE(this, "failed enabling flash (%s)\n", + NAME_OF(clearpad_flash_status_name, + BIT_GET(buf[0], STATUS_FLASH_STATUS))); + rc = -EIO; + goto end; + } + + HWLOGI(this, "flashing enabled\n"); + + if (this->state == SYN_STATE_FLASH_ENABLE) { + /* PDT may have changed, re-read */ + rc = clearpad_read_pdt(this); + if (rc) { + HWLOGE(this, "failed to read pdt\n"); + goto end; + } + } + + /* read bootloader id */ + rc = clearpad_get_block(SYNF(this, F34_FLASH, QUERY, + this->reg_offset.f34_query00), buf, sizeof(buf)); + if (rc) + goto end; + + /* write bootloader id to block data */ + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data01), buf, sizeof(buf)); + if (rc) + goto end; + + if (this->state == SYN_STATE_FLASH_ENABLE && + (flash->command == SYN_FORCE_FLASH || + flash->command == SYN_DEFAULT_FLASH)) { + rc = clearpad_put(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data02), + FLASH_CONTROL_ERASE_ALL); + if (rc) + goto end; + this->state = SYN_STATE_FLASH_PROGRAM; + } else if ((this->state == SYN_STATE_FLASH_PROGRAM && + (flash->command == SYN_FORCE_FLASH || + flash->command == SYN_DEFAULT_FLASH))) { + rc = clearpad_put(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data02), + FLASH_CONTROL_ERASE_CONFIGURATION); + if (rc) + goto end; + this->state = SYN_STATE_FLASH_ERASE; + } else { + HWLOGE(this, "invalid state(%s) for command(%s)\n", + NAME_OF(clearpad_state_name, this->state), + NAME_OF(clearpad_flash_command_name, flash->command)); + rc = -EINVAL; + goto end; + } + + HWLOGI(this, "firmware erasing\n"); +end: + return rc; +} + +static int clearpad_flash_update_bl_v6_0(struct clearpad_t *this) +{ + struct clearpad_flash_t *flash = &this->flash; + int rc, len; + const u8 *data; + u8 buf, pid; + struct clearpad_flash_block_t *object; + enum clearpad_state_e finish_state; + u8 pos[2]; + + if (this->state == SYN_STATE_FLASH_ERASE && + (flash->command == SYN_FORCE_FLASH || + flash->command == SYN_DEFAULT_FLASH)) { + object = &(&this->flash)->data; + pid = PID_CORE_CODE; + finish_state = SYN_STATE_FLASH_DATA; + } else if ((this->state == SYN_STATE_FLASH_DATA && + (flash->command == SYN_FORCE_FLASH || + flash->command == SYN_DEFAULT_FLASH))) { + object = &(&this->flash)->config; + pid = PID_CORE_CONFIGURATION; + finish_state = SYN_STATE_FLASH_CONFIG; + } else { + HWLOGE(this, "invalid state(%s) for command(%s)\n", + NAME_OF(clearpad_state_name, this->state), + NAME_OF(clearpad_flash_command_name, flash->command)); + rc = -EINVAL; + goto end; + } + + if (object->pos > 0) + goto write_block_data; + + /* make sure that we are in programming mode and there are no issues */ + rc = clearpad_get(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data03), &buf); + if (rc) { + HWLOGE(this, "failed to get flash programming status\n"); + goto end; + } + + if (!(BIT_GET(buf, STATUS_BL_MODE))) { + HWLOGE(this, "failed flashing in %s (%s)\n", + NAME_OF(clearpad_state_name, this->state), + NAME_OF(clearpad_flash_status_name, + BIT_GET(buf, STATUS_FLASH_STATUS))); + rc = -EIO; + goto end; + } + + object->payload_length = SYN_PAYLOAD_LENGTH; + + /* block # low and high byte */ + pos[0] = object->pos & 0xff; + pos[1] = (object->pos >> 8) & 0xff; + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data00), pos, 2); + if (rc) + goto end; + +write_block_data: + data = object->data + object->pos * 16; + len = object->length - object->pos * 16; + if (len > 16) + len = 16; + + /* write block data */ + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data01), data, len); + if (rc) + goto end; + /* issue a write data block command */ + if (pid == PID_CORE_CODE) + rc = clearpad_put(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data02), + FLASH_CONTROL_WRITE_FIRMWARE_BLOCK); + else + rc = clearpad_put(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data02), + FLASH_CONTROL_WRITE_CONFIGURATION_BLOCK); + if (rc) + goto end; + + if (object->pos % 100 == 0) + LOGI(this, "wrote %d blocks\n", object->pos); + + /* if we've reached the end of the data/configuration flashing */ + if (++object->pos == object->blocks) { + HWLOGI(this, "flash finished on %s\n", + NAME_OF(clearpad_state_name, this->state)); + this->state = finish_state; + } +end: + return rc; +} + +static int clearpad_flash_disable_bl_v6_0(struct clearpad_t *this) +{ + int rc; + u8 buf; + + /* make sure that we are in programming mode and there are no issues */ + rc = clearpad_get(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data03), &buf); + if (rc) + goto end; + + if (!(BIT_GET(buf, STATUS_BL_MODE))) { + HWLOGE(this, "failed flashing config (%s)\n", + NAME_OF(clearpad_flash_status_name, + BIT_GET(buf, STATUS_FLASH_STATUS))); + rc = -EIO; + goto end; + } + + clearpad_set_delay(SYN_WAIT_TIME_AFTER_REGISTER_ACCESS); + + /* send a reset to the device to complete the flash procedure */ + clearpad_reset(this, SYN_SWRESET, __func__); + + HWLOGI(this, "flashing finished, resetting\n"); + this->state = SYN_STATE_FLASH_DISABLE; +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_flash_bl_v6_0(struct clearpad_t *this) +{ + int rc = 0; + + switch (this->state) { + case SYN_STATE_FLASH_IMAGE_SET: + rc = clearpad_flash_enable_bl_v6_0(this); + break; + case SYN_STATE_FLASH_ENABLE: + case SYN_STATE_FLASH_PROGRAM: + rc = clearpad_flash_program_bl_v6_0(this); + break; + case SYN_STATE_FLASH_ERASE: + case SYN_STATE_FLASH_DATA: + rc = clearpad_flash_update_bl_v6_0(this); + break; + case SYN_STATE_FLASH_CONFIG: + rc = clearpad_flash_disable_bl_v6_0(this); + clearpad_firmware_reset(this); + break; + case SYN_STATE_FLASH_DISABLE: + HWLOGE(this, "should be handled by clearpad_initialize\n"); + break; + default: + HWLOGE(this, "invalid state(%s)", + NAME_OF(clearpad_state_name, this->state)); + rc = -EINVAL; + break; + } + return rc; +} + +/* for Bootloader v7.x */ +static int clearpad_flash_enable_bl_v7_x(struct clearpad_t *this) +{ + int rc; + u8 buf[SYN_SINGLE_TRANSACTION_SIZE] = { + PID_BOOTLOADER, 0x00, 0x00, 0x00, 0x00, + FLASH_CMD_ENTER_BOOTLOADER}; + + /* set device configured bit */ + /* F01_RMI_CTRL00: Device Control */ + rc = clearpad_put_bit(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), + DEVICE_CONTROL_CONFIGURED_MASK, + DEVICE_CONTROL_CONFIGURED_MASK); + if (rc) { + HWLOGE(this, "failed to set device configured bit\n"); + goto end; + } + clearpad_set_delay(SYN_WAIT_TIME_AFTER_REGISTER_ACCESS); + + /* read flash program key */ + rc = clearpad_get_block(SYNF(this, F34_FLASH, QUERY, + this->reg_offset.f34_query01), + buf + SYN_FP_KEY_OFFSET, 2); + if (rc) { + HWLOGE(this, "failed to read flash program key\n"); + goto end; + } + + /* issue command to enter bootloader mode with key*/ + this->flash.enter_bootloader_mode = true; + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data01), + buf, sizeof(buf)); + + if (rc) { + HWLOGE(this, "failed to enter bootloader mode\n"); + goto end; + } + + this->state = SYN_STATE_FLASH_ENABLE; + +end: + return rc; +} + +static int clearpad_flash_program_bl_v7_x(struct clearpad_t *this) +{ + struct clearpad_flash_t *flash = &this->flash; + int rc; + u8 buf[SYN_SINGLE_TRANSACTION_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, FLASH_CMD_ERASE}; + + /* make sure that we are in programming mode and there are no issues */ + rc = clearpad_get(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data00), buf); + if (rc) { + HWLOGE(this, "failed to get flash programming status\n"); + goto end; + } + + if (!(BIT_GET(buf[0], STATUS_BL_MODE))) { + HWLOGE(this, "failed enabling flash (%s)\n", + NAME_OF(clearpad_flash_status_name, + BIT_GET(buf[0], STATUS_FLASH_STATUS))); + rc = -EIO; + goto end; + } + + HWLOGI(this, "flashing enabled\n"); + + if (this->state == SYN_STATE_FLASH_ENABLE) { + /* PDT may have changed, re-read */ + rc = clearpad_read_pdt(this); + if (rc) { + HWLOGE(this, "failed to read pdt\n"); + goto end; + } + } + + /* read flash program key */ + rc = clearpad_get_block(SYNF(this, F34_FLASH, QUERY, + this->reg_offset.f34_query01), + buf + SYN_FP_KEY_OFFSET, 2); + if (rc) { + HWLOGE(this, "failed to flash program key\n"); + goto end; + } + + if (this->state == SYN_STATE_FLASH_ENABLE && + (flash->command == SYN_FORCE_FLASH || + flash->command == SYN_DEFAULT_FLASH)) { + buf[0] = PID_CORE_CODE; + this->state = SYN_STATE_FLASH_PROGRAM; + } else if ((this->state == SYN_STATE_FLASH_PROGRAM && + (flash->command == SYN_FORCE_FLASH || + flash->command == SYN_DEFAULT_FLASH))) { + buf[0] = PID_CORE_CONFIGURATION; + this->state = SYN_STATE_FLASH_ERASE; + } else { + HWLOGE(this, "invalid state(%s) for command(%s)\n", + NAME_OF(clearpad_state_name, this->state), + NAME_OF(clearpad_flash_command_name, flash->command)); + rc = -EINVAL; + goto end; + } + + /* issue command to erase partition with key*/ + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data01), buf, sizeof(buf)); + if (rc) { + HWLOGE(this, "failed to erase partition with key\n"); + goto end; + } + + HWLOGI(this, "firmware erasing\n"); +end: + return rc; +} + +static int clearpad_flash_update_bl_v7_x(struct clearpad_t *this) +{ + struct clearpad_flash_t *flash = &this->flash; + int rc, len; + const u8 *data; + u8 buf, pid; + u8 block_buf[3]; + u16 block_num = 0; + struct clearpad_flash_block_t *object; + enum clearpad_state_e finish_state; + + if (this->state == SYN_STATE_FLASH_ERASE && + (flash->command == SYN_FORCE_FLASH || + flash->command == SYN_DEFAULT_FLASH)) { + object = &(&this->flash)->data; + pid = PID_CORE_CODE; + finish_state = SYN_STATE_FLASH_DATA; + } else if ((this->state == SYN_STATE_FLASH_DATA && + (flash->command == SYN_FORCE_FLASH || + flash->command == SYN_DEFAULT_FLASH))) { + object = &(&this->flash)->config; + pid = PID_CORE_CONFIGURATION; + finish_state = SYN_STATE_FLASH_CONFIG; + } else { + HWLOGE(this, "invalid state(%s) for command(%s)\n", + NAME_OF(clearpad_state_name, this->state), + NAME_OF(clearpad_flash_command_name, flash->command)); + rc = -EINVAL; + goto end; + } + + if (object->pos > 0) + goto write_block_data; + + /* make sure that we are in programming mode and there are no issues */ + rc = clearpad_get(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data00), &buf); + if (rc) { + HWLOGE(this, "failed to get flash programming status\n"); + goto end; + } + + if (!(BIT_GET(buf, STATUS_BL_MODE))) { + HWLOGE(this, "failed flashing in %s (%s)\n", + NAME_OF(clearpad_state_name, this->state), + NAME_OF(clearpad_flash_status_name, + BIT_GET(buf, STATUS_FLASH_STATUS))); + rc = -EIO; + goto end; + } + + object->payload_length = SYN_PAYLOAD_LENGTH; + + /* read block size */ + rc = clearpad_get_block(SYNF(this, F34_FLASH, QUERY, + this->reg_offset.f34_query03), + block_buf, 3); + if (rc) { + HWLOGE(this, "unable to read block size of fw\n"); + goto end; + } + + object->block_size = ((block_buf[2] << 8) | block_buf[1]); + + object->remain_block = (object->length / object->block_size) + % object->payload_length; + object->transation_count = (object->length / object->block_size) + / object->payload_length; + object->blocks = (object->length / object->block_size) + + !!(object->length % object->block_size); + + if (object->remain_block > 0) + object->transation_count++; + + /* write partition id */ + rc = clearpad_put(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data01), pid); + if (rc) { + HWLOGE(this, "unable to write partition id\n"); + goto end; + } + + /* write block num */ + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data02), + (u8 *)&block_num, 2); + if (rc) { + HWLOGE(this, "unable to write block number\n"); + goto end; + } + +write_block_data: + if ((object->pos == (object->transation_count - 1)) + && (object->remain_block > 0)) + object->payload_length = object->remain_block; + + data = object->data + object->pos * object->block_size; + len = object->length - object->pos * object->block_size; + + if (len > object->block_size) + len = object->block_size; + + /* write payload length */ + rc = clearpad_put_block(SYNF( + this, F34_FLASH, DATA, this->reg_offset.f34_data03), + (u8 *)&(object->payload_length), 2); + if (rc) { + HWLOGE(this, "unable to write payload length\n"); + goto end; + } + + /* write command */ + rc = clearpad_put( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data04), + FLASH_CMD_WRITE); + if (rc) { + HWLOGE(this, "unable to write flash cmd\n"); + goto end; + } + + /* issue a write data/configuration block command with data */ + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data05), data, len); + if (rc) { + HWLOGE(this, "unable to write data/configuration block cmd\n"); + goto end; + } + + if (object->pos % 100 == 0) + LOGI(this, "wrote %d blocks\n", object->pos); + + /* if we've reached the end of the data/configuration flashing */ + if (++object->pos == object->blocks) { + HWLOGI(this, "flash finished on %s\n", + NAME_OF(clearpad_state_name, this->state)); + this->state = finish_state; + } +end: + return rc; +} + +static int clearpad_flash_disable_bl_v7_x(struct clearpad_t *this) +{ + int rc; + u8 buf; + + /* make sure that we are in programming mode and there are no issues */ + rc = clearpad_get(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data00), &buf); + if (rc) + goto end; + + if (!(BIT_GET(buf, STATUS_BL_MODE))) { + HWLOGE(this, "failed flashing config (%s)\n", + NAME_OF(clearpad_flash_status_name, + BIT_GET(buf, STATUS_FLASH_STATUS))); + rc = -EIO; + goto end; + } + + clearpad_set_delay(SYN_WAIT_TIME_AFTER_REGISTER_ACCESS); + + /* send a reset to the device to complete the flash procedure */ + clearpad_reset(this, SYN_SWRESET, __func__); + + HWLOGI(this, "flashing finished, resetting\n"); + this->state = SYN_STATE_FLASH_DISABLE; +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_flash_bl_v7_x(struct clearpad_t *this) +{ + int rc = 0; + + switch (this->state) { + case SYN_STATE_FLASH_IMAGE_SET: + rc = clearpad_flash_enable_bl_v7_x(this); + break; + case SYN_STATE_FLASH_ENABLE: + case SYN_STATE_FLASH_PROGRAM: + rc = clearpad_flash_program_bl_v7_x(this); + break; + case SYN_STATE_FLASH_ERASE: + case SYN_STATE_FLASH_DATA: + rc = clearpad_flash_update_bl_v7_x(this); + break; + case SYN_STATE_FLASH_CONFIG: + rc = clearpad_flash_disable_bl_v7_x(this); + clearpad_firmware_reset(this); + break; + case SYN_STATE_FLASH_DISABLE: + HWLOGE(this, "should be handled by clearpad_initialize\n"); + break; + default: + HWLOGE(this, "invalid state(%s)", + NAME_OF(clearpad_state_name, this->state)); + rc = -EINVAL; + break; + } + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_flash(struct clearpad_t *this) +{ + int rc = 0; + + LOGD(this, "flash state=%s\n", + NAME_OF(clearpad_state_name, this->state)); + + if (this->is_sol) + rc = clearpad_flash_bl_v6_0(this); + else + rc = clearpad_flash_bl_v7_x(this); + if (rc) { + HWLOGE(this, "failed during flash (%s), rc = %d\n", + NAME_OF(clearpad_state_name, this->state), rc); + + snprintf(this->result_info, SYN_STRING_LENGTH, + "%s, family 0x%02x, fw rev 0x%02x.%02x, " + "extra 0x%02x, failed fw update\n", + clearpad_s(this->device_info.product_id, + HEADER_PRODUCT_ID_SIZE), + this->device_info.customer_family, + this->device_info.firmware_revision_major, + this->device_info.firmware_revision_minor, + this->device_info.firmware_revision_extra); + this->flash_requested = false; + clearpad_firmware_reset(this); + HWLOGI(this, "result: %s", this->result_info); + + if (this->state != SYN_STATE_FLASH_IMAGE_SET) + clearpad_notify_interrupt(this, + &this->interrupt.for_reset, rc); + } + return rc; +} + +/* need LOCK(&this->lock) */ +bool clearpad_is_healthy(struct clearpad_t *this) +{ + u8 status = 0; + int rc = 0; + + switch (this->chip_id) { + case SYN_CHIP_332U: + /* F01_RMI_CTRL00: Device Control */ + rc = clearpad_get(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), &status); + if (rc) { + LOGE(this, "rc=%d\n", rc); + return false; + } + if (BIT_GET(status, DEVICE_CONTROL_CONFIGURED)) { + LOGE(this, "status=0x%02x\n", status); + return false; + } + /* fall-through */ + case SYN_CHIP_3330: + case SYN_CHIP_3500: + /* F01_RMI_DATA00: Device Status */ + rc = clearpad_get(SYNF(this, F01_RMI, DATA, + this->reg_offset.f01_data00), &status); + if (rc) { + LOGE(this, "rc=%d\n", rc); + return false; + } + if (BIT_GET(status, DEVICE_STATUS_CODE)) { + LOGE(this, "status=0x%02x\n", status); + switch (BIT_GET(status, DEVICE_STATUS_CODE)) { + case DEVICE_STATUS_CODE_DEVICE_FAILURE: + case DEVICE_STATUS_CODE_CONFIGURATION_CRC_FAILURE: + case DEVICE_STATUS_CODE_FIRMWARE_CRC_FAILURE: + case DEVICE_STATUS_CODE_GUEST_CRC_FAILURE: + case DEVICE_STATUS_CODE_EXTERNAL_AFE_FAILURE: + case DEVICE_STATUS_CODE_DISPLAY_FAILURE: + return false; + default: + return true; + } + } + break; + default: + LOGE(this, "not supported chip id (0x%02x)\n", this->chip_id); + rc = -EINVAL; + break; + } + return true; +} + +static void clearpad_watchdog_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct clearpad_watchdog_t *wd = (struct clearpad_watchdog_t *)dwork; + struct clearpad_t *this = container_of(wd, struct clearpad_t, watchdog); + bool healthy = true; + int rc; + + LOGD(this, "start\n"); + + LOCK(&this->lock); + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + + if (!this->touchctrl.will_powerdown && !this->flash_requested) + schedule_delayed_work(&this->watchdog.work, + this->watchdog.delay); + + goto not_ready_to_access_i2c; + } + + if (!touchctrl_lock_power(this, __func__, true, false)) { + LOG_STAT(this, "stop watchdog because of no lock power\n"); + UNLOCK(&this->lock); + return; + } + + if (this->dev_active && !this->flash_requested) + healthy = clearpad_is_healthy(this); + LOG_STAT(this, "%s (icount=%u)\n", + healthy ? "healthy" : "NEED HW RESET", this->interrupt.count); + if (!healthy) { + clearpad_debug_info(this); + clearpad_reset(this, SYN_HWRESET, "Watchdog"); + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_reset, + this->interrupt.wait_ms); + LOCK(&this->lock); + if (rc) + LOGE(this, "failed to get interrupt (rc=%d)\n", rc); + } + if (this->dev_active && !this->flash_requested) + schedule_delayed_work(&this->watchdog.work, + this->watchdog.delay); + touchctrl_unlock_power(this, __func__); +not_ready_to_access_i2c: + UNLOCK(&this->lock); +} + +/* need LOCK(&this->lock) */ +static void clearpad_watchdog_update(struct clearpad_t *this) +{ + if (!this->watchdog.enabled) + return; + + cancel_delayed_work(&this->watchdog.work); + + if (this->dev_active && !this->flash_requested) + schedule_delayed_work(&this->watchdog.work, + this->watchdog.delay); +} + +/* need LOCK(&this->lock) */ +static int clearpad_set_resume_mode(struct clearpad_t *this) +{ + int rc = 0; + u8 interrupt; + u8 value; + + HWLOGI(this, "set resume mode\n"); + WARN_ON(this->dev_active && !this->early_suspend); + + if (this->post_probe.done) + clearpad_funcarea_invalidate_all(this); + + /* F01_RMI_CTRL01.00: Interrupt Enable 0 */ + rc = clearpad_put(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl01), + INTERRUPT_ENABLE_0_ENABLE_ALL); + if (rc) { + LOGE(this, "failed to set interrupt enable\n"); + goto end; + } + + /* F01_RMI_CTRL00: Device Control */ + rc = clearpad_get(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), &value); + if (rc) { + LOGE(this, "failed to get sleep status\n"); + goto end; + } + if (BIT_GET(value, DEVICE_CONTROL_SLEEP_MODE)) { + rc = clearpad_put_bit(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), + DEVICE_CONTROL_SLEEP_MODE_NORMAL_OPERATION, + DEVICE_CONTROL_SLEEP_MODE_MASK); + if (rc) { + LOGE(this, "failed to exit sleep mode\n"); + goto end; + } + clearpad_set_delay(this->charger_only.delay_ms); + } + + this->early_suspend = false; + + if (this->wakeup_gesture.enabled) { + rc = clearpad_disable_wakeup_gesture(this); + if (rc) { + LOGE(this, "failed to disable wakeup gesture\n"); + goto end; + } + } + + if (this->cover.enabled) + rc = clearpad_set_cover_status(this); + + this->dev_active = true; + + if (clearpad_set_noise_det_irq(this, true, true)) + HWLOGI(this, "no noise_det irq change (enable)\n"); + else + LOGI(this, "noise_det irq was enabled\n"); + + if (!this->irq_enabled) { + /* F01_RMI_DATA01: Interrupt Status */ + rc = clearpad_get(SYNF(this, F01_RMI, DATA, + this->reg_offset.f01_data01), &interrupt); + if (rc) { + LOGE(this, "failed to read interrupt status\n"); + goto end; + } + LOGI(this, "ignore interrupt 0x%02x\n", interrupt); + clearpad_set_irq(this, true); + } + +end: + LOGI(this, "set resume mode (rc=%d)\n", rc); + return rc; +} + +/* This function is called from touch backlight daemon context + * while clearpad_set_suspend_mode() is called from EARLY POWERDOWN. + * + * need LOCK(&this->lock) + */ +static int clearpad_set_early_suspend_mode(struct clearpad_t *this) +{ + int rc = 0; + + HWLOGI(this, "set early suspend mode\n"); + + if (this->force_sleep != FSMODE_KEEP) { + /* F01_RMI_CTRL01.00: Interrupt Enable 0 */ + rc = clearpad_put(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl01), + INTERRUPT_ENABLE_0_DISABLE_ALL); + if (rc) { + LOGE(this, "failed to disable interrupt mode\n"); + goto end; + } + } else { + /* F01_RMI_CTRL00: Device Control */ + rc = clearpad_put_bit(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), + DEVICE_CONTROL_SLEEP_MODE_SENSOR_SLEEP, + DEVICE_CONTROL_SLEEP_MODE_MASK); + if (rc) { + LOGE(this, "failed to exit normal mode\n"); + goto end; + } + clearpad_set_delay(this->charger_only.delay_ms); + } + clearpad_set_irq(this, false); + this->early_suspend = true; + + HWLOGI(this, "enter sleep mode\n"); +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_set_suspend_mode(struct clearpad_t *this) +{ + int rc = 0; + + if (this->dev_active) + HWLOGI(this, "set suspend mode\n"); + else + HWLOGI(this, "change suspend mode\n"); + + if (this->force_sleep != FSMODE_KEEP && + this->wakeup_gesture.enabled) { + HWLOGI(this, "prepare for wakeup gesture mode"); + if (this->early_suspend) { + /* F01_RMI_CTRL01.00: Interrupt Enable 0 */ + rc = clearpad_put(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl01), + INTERRUPT_ENABLE_0_ENABLE_ALL); + if (rc) { + LOGE(this, "failed to exit sleep mode\n"); + goto end; + } + } + + rc = clearpad_enable_wakeup_gesture(this); + if (rc) { + LOGE(this, "failed to enable wakeup gesture\n"); + goto end; + } + + this->wakeup_gesture.time_started = jiffies - 1; + clearpad_set_delay(SYN_WAIT_TIME_AFTER_REGISTER_ACCESS); + clearpad_set_irq(this, true); + HWLOGI(this, "enter wakeup gesture mode\n"); + } else { + if (!this->early_suspend) { + if (this->force_sleep != FSMODE_KEEP) { + /* F01_RMI_CTRL01.00: Interrupt Enable 0 */ + rc = clearpad_put(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl01), + INTERRUPT_ENABLE_0_DISABLE_ALL); + if (rc) { + LOGE(this, "failed to set interrupt" + "disable\n"); + goto end; + } + } else { + /* F01_RMI_CTRL00: Device Control */ + rc = clearpad_put_bit( + SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), + DEVICE_CONTROL_SLEEP_MODE_SENSOR_SLEEP, + DEVICE_CONTROL_SLEEP_MODE_MASK); + if (rc) { + LOGE(this, "failed to exit normal" + "mode\n"); + goto end; + } + clearpad_set_delay(this->charger_only.delay_ms); + } + clearpad_set_irq(this, false); + HWLOGI(this, "enter sleep mode\n"); + } else { + HWLOGI(this, "already in sleep mode\n"); + } + } + + this->dev_active = false; + + if (clearpad_set_noise_det_irq(this, false, false)) + HWLOGI(this, "no noise_det irq change (disable)\n"); + else + LOGI(this, "noise_det irq was disabled\n"); + +end: + if (rc) + LOGI(this, "set suspend mode (rc=%d)\n", rc); + + return rc; +} + +/* + * Reset + */ + +static void clearpad_reset_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct clearpad_reset_t *reset + = container_of(dwork, struct clearpad_reset_t, work); + struct clearpad_t *this + = container_of(reset, struct clearpad_t, reset); + int retry = 0; + int rc; + unsigned long flags; + + LOGI(this, "start %s '%s'\n", + NAME_OF(clearpad_reset_name, reset->mode), + this->interrupt.for_reset.name); + + LOCK(&this->lock); + if (!touchctrl_lock_power(this, __func__, true, false)) { + LOG_STAT(this, "stop reset work because of no power\n"); + clearpad_notify_interrupt(this, + &this->interrupt.for_reset, -EPERM); + goto err_in_lock_power; + } + +retry_reset: + this->interrupt.count = 0; /* to detect first interrupt */ + spin_lock_irqsave(&this->slock, flags); + this->dev_busy = false; + this->irq_pending = false; + spin_unlock_irqrestore(&this->slock, flags); + switch (reset->mode) { + case SYN_HWRESET: + case SYN_FORCE_HWRESET: + rc = touchctrl_hwreset(this, reset->mode); + if (rc && retry++ < SYN_RETRY_NUM_OF_RESET) + goto retry_reset; + break; + case SYN_SWRESET: + case SYN_FORCE_SWRESET: + /* F01_RMI_CMD00: Device Command */ + rc = clearpad_put( + SYNF(this, F01_RMI, COMMAND, + this->reg_offset.f01_cmd00), + DEVICE_COMMAND_RESET_MASK); + if (rc && retry++ < SYN_RETRY_NUM_OF_RESET) + goto retry_reset; + break; + default: + rc = -EINVAL; + LOGE(this, "invalid mode %d\n", reset->mode); + break; + } + LOGW(this, "state '%s' was interrupted by reset\n", + NAME_OF(clearpad_state_name, this->state)); + /* will be changed to RUNNING by clearpad_initialize */ + this->state = SYN_STATE_DISABLED; + /* inform about this reset to running session */ + clearpad_notify_interrupt(this, &this->interrupt.for_F34, -EINTR); + clearpad_notify_interrupt(this, &this->interrupt.for_F54, -EINTR); + + if ((rc == -EAGAIN || rc == -EBUSY) && + reset->retry++ < SYN_RETRY_NUM_OF_RESET) { + LOGI(this, "schedule reset for retry (rc=%d)\n", rc); + schedule_delayed_work(&reset->work, 1 * HZ); + } else if (rc) { + LOGE(this, "failed to execute %s '%s'\n", + NAME_OF(clearpad_reset_name, reset->mode), + this->interrupt.for_reset.name); + clearpad_notify_interrupt(this, + &this->interrupt.for_reset, rc); + } + if (this->watchdog.enabled) + clearpad_watchdog_update(this); + + touchctrl_unlock_power(this, __func__); + LOGI(this, "done\n"); +err_in_lock_power: + UNLOCK(&this->lock); + return; +} + +/* + * request asynchronized reset + * need LOCK(&this->lock) */ +static void clearpad_reset(struct clearpad_t *this, + enum clearpad_reset_e mode, const char *cause) +{ + struct clearpad_reset_t *reset = &this->reset; + + if (!this->dev_active + && mode != SYN_FORCE_HWRESET && mode != SYN_FORCE_SWRESET) { + HWLOGW(this, "could not execute %s because " + "device is suspended and not force reset\n", + NAME_OF(clearpad_reset_name, mode)); + goto err_in_device_mode; + } + + if (atomic_read(&this->interrupt.for_reset.done) == 0 && + this->interrupt.for_reset.name) { + LOGI(this, "request %s '%s' continued to %s '%s'\n", + NAME_OF(clearpad_reset_name, mode), cause, + NAME_OF(clearpad_reset_name, reset->mode), + this->interrupt.for_reset.name); + } + + if (this->watchdog.enabled) + cancel_delayed_work(&this->watchdog.work); + + reset->mode = mode; + this->interrupt.for_reset.name = cause; + clearpad_prepare_for_interrupt(this, &this->interrupt.for_reset, cause); + + reset->retry = 0; + LOGE(this, "schedule %s '%s'\n", + NAME_OF(clearpad_reset_name, mode), cause); + if (!schedule_delayed_work(&reset->work, 0)) + LOGI(this, "already reset on queue\n"); + +err_in_device_mode: + return; +} + +static int clearpad_gpio_export(struct clearpad_t *this, + struct device *dev, bool export) +{ + int rc = 0; + + if (export) { + rc = gpio_export(this->pdata->irq_gpio, false); + if (rc) { + LOGE(this, "failed to export gpio (rc=%d)\n", rc); + } else { + rc = gpio_export_link(dev, "attn", + this->pdata->irq_gpio); + if (rc) + LOGE(this, "failed to export (rc=%d)\n", rc); + } + if (this->noise_det.supported) { + rc = gpio_export(this->noise_det.irq_gpio, false); + if (rc) { + LOGE(this, "failed to export noise_det gpio\n" + " (rc=%d)\n", rc); + } else { + rc = gpio_export_link(dev, "noise_det", + this->noise_det.irq_gpio); + if (rc) + LOGE(this, + "failed to export noise_det link" + " (rc=%d)\n", rc); + } + } + } else { + gpio_unexport(this->pdata->irq_gpio); + sysfs_remove_link(&dev->kobj, "attn"); + if (this->noise_det.supported) { + gpio_unexport(this->noise_det.irq_gpio); + sysfs_remove_link(&dev->kobj, "noise_det"); + } + } + + return rc; +} + +static void clearpad_funcarea_initialize(struct clearpad_t *this) +{ + struct clearpad_funcarea_t *funcarea; + struct clearpad_area_t pointer_area; + struct clearpad_button_data_t *button; + struct clearpad_pointer_data_t *pointer_data; + static const char const *func_name[] = { + [SYN_FUNCAREA_INSENSIBLE] = "insensible", + [SYN_FUNCAREA_POINTER] = "pointer", + [SYN_FUNCAREA_BUTTON] = "button", + }; + + this->funcarea = clearpad_funcarea_get(this, + this->device_info.customer_family, + this->device_info.firmware_revision_major); + funcarea = this->funcarea; + + if (funcarea == NULL) { + LOGI(this, "no funcarea\n"); + return; + } + + for (; funcarea->func != SYN_FUNCAREA_END; funcarea++) { + switch (funcarea->func) { + case SYN_FUNCAREA_POINTER: + pointer_area = (struct clearpad_area_t) + funcarea->original; + pointer_data = (struct clearpad_pointer_data_t *) + funcarea->data; + if (pointer_data) { + pointer_area.x1 -= pointer_data->offset_x; + pointer_area.x2 -= pointer_data->offset_x; + pointer_area.y1 -= pointer_data->offset_y; + pointer_area.y2 -= pointer_data->offset_y; + } + input_set_abs_params(this->input, ABS_MT_TRACKING_ID, + 0, this->extents.n_fingers, 0, 0); + input_set_abs_params(this->input, ABS_MT_POSITION_X, + pointer_area.x1, + pointer_area.x2, 0, 0); + input_set_abs_params(this->input, ABS_MT_POSITION_Y, + pointer_area.y1, + pointer_area.y2, 0, 0); + if (this->touch_pressure_enabled) + input_set_abs_params(this->input, + ABS_MT_PRESSURE, 0, + SYN_MAX_Z_VALUE, 0, 0); + if (this->touch_size_enabled) { + input_set_abs_params(this->input, + ABS_MT_TOUCH_MAJOR, 0, + SYN_MAX_W_VALUE + 1, 0, 0); + input_set_abs_params(this->input, + ABS_MT_TOUCH_MINOR, 0, + SYN_MAX_W_VALUE + 1, 0, 0); + } + if (this->touch_orientation_enabled) + input_set_abs_params(this->input, + ABS_MT_ORIENTATION, -1, 1, 0, 0); + input_set_abs_params(this->input, ABS_MT_TOOL_TYPE, + 0, this->pen.enabled ? MT_TOOL_PEN : + MT_TOOL_FINGER, 0, 0); + break; + case SYN_FUNCAREA_BUTTON: + button = + (struct clearpad_button_data_t *)funcarea->data; + input_set_capability(this->input, EV_KEY, button->code); + break; + default: + continue; + } + + LOGI(this, "funcarea '%s' [%d, %d, %d, %d] [%d, %d, %d, %d]\n", + NAME_OF(func_name, funcarea->func), + funcarea->original.x1, funcarea->original.y1, + funcarea->original.x2, funcarea->original.y2, + funcarea->extension.x1, funcarea->extension.y1, + funcarea->extension.x2, funcarea->extension.y2); + } +} + +static inline bool clearpad_funcarea_test(struct clearpad_area_t *area, + struct clearpad_point_t *point) +{ + return area->x1 <= point->x && point->x <= area->x2 + && area->y1 <= point->y && point->y <= area->y2; +} + +static struct clearpad_funcarea_t * +clearpad_funcarea_search(struct clearpad_t *this, + struct clearpad_pointer_t *pointer) +{ + struct clearpad_funcarea_t *funcarea = this->funcarea; + + if (funcarea == NULL) + goto end; + + /* get new funcarea */ + for (; funcarea->func != SYN_FUNCAREA_END; funcarea++) { + if (clearpad_funcarea_test(&funcarea->original, + &pointer->cur)) + goto end; + if (funcarea->func == SYN_FUNCAREA_POINTER + && clearpad_funcarea_test(&funcarea->extension, + &pointer->cur)) + goto end; + } + funcarea = NULL; +end: + return funcarea; +} + +static void clearpad_funcarea_crop(struct clearpad_area_t *area, + struct clearpad_point_t *point) +{ + + if (point->x < area->x1) + point->x = area->x1; + else if (area->x2 < point->x) + point->x = area->x2; + + if (point->y < area->y1) + point->y = area->y1; + else if (area->y2 < point->y) + point->y = area->y2; + +} + +static void clearpad_funcarea_down(struct clearpad_t *this, + struct clearpad_pointer_t *pointer) +{ + int touch_major, touch_minor; + struct clearpad_button_data_t *button; + struct clearpad_pointer_data_t *pointer_data; + struct clearpad_point_t *cur = &pointer->cur; + struct input_dev *idev = this->input; + bool valid; + + switch (pointer->funcarea->func) { + case SYN_FUNCAREA_INSENSIBLE: + LOG_EVENT(this, "insensible\n"); + pointer->down = false; + break; + case SYN_FUNCAREA_POINTER: + clearpad_funcarea_crop(&pointer->funcarea->original, cur); + pointer_data = (struct clearpad_pointer_data_t *) + pointer->funcarea->data; + if (pointer_data) { + cur->x -= pointer_data->offset_x; + cur->y -= pointer_data->offset_y; + } + if (cur->tool == SYN_TOOL_PEN) { + cur->tool = MT_TOOL_PEN; + } else { + /* shift range if glove event */ + if (cur->tool == SYN_TOOL_GLOVE) { + if (cur->z > 0) + cur->z += SYN_MAX_Z_VALUE + 1; + else + cur->z = 0; + } else { + if (cur->z > SYN_MAX_Z_VALUE) + cur->z = SYN_MAX_Z_VALUE; + } + cur->tool = MT_TOOL_FINGER; + } + valid = idev->users > 0; + LOG_EVENT(this, "%s[%d]: (x,y)=(%d,%d) w=(%d,%d) z=%d t=%d\n", + valid ? "pt" : "unused pt", cur->id, cur->x, cur->y, + cur->wx, cur->wy, cur->z, cur->tool); + if (!valid) + break; + touch_major = max(cur->wx, cur->wy) + 1; + touch_minor = min(cur->wx, cur->wy) + 1; + input_report_abs(idev, ABS_MT_TRACKING_ID, cur->id); + input_report_abs(idev, ABS_MT_TOOL_TYPE, cur->tool); + input_report_abs(idev, ABS_MT_POSITION_X, cur->x); + input_report_abs(idev, ABS_MT_POSITION_Y, cur->y); + if (this->touch_pressure_enabled) + input_report_abs(idev, ABS_MT_PRESSURE, cur->z); + if (this->touch_size_enabled) { + input_report_abs(idev, ABS_MT_TOUCH_MAJOR, touch_major); + input_report_abs(idev, ABS_MT_TOUCH_MINOR, touch_minor); + } + if (this->touch_orientation_enabled) + input_report_abs(idev, ABS_MT_ORIENTATION, + (cur->wx > cur->wy)); + input_mt_sync(idev); + break; + case SYN_FUNCAREA_BUTTON: + LOG_EVENT(this, "button\n"); + button = (struct clearpad_button_data_t *) + pointer->funcarea->data; + if (button) + button->down = true; + break; + default: + break; + } +} + +static void clearpad_funcarea_up(struct clearpad_t *this, + struct clearpad_pointer_t *pointer) +{ + struct clearpad_button_data_t *button; + struct input_dev *idev = this->input; + bool valid; + + switch (pointer->funcarea->func) { + case SYN_FUNCAREA_INSENSIBLE: + LOG_EVENT(this, "insensible up\n"); + break; + case SYN_FUNCAREA_POINTER: + valid = idev->users > 0; + LOG_EVENT(this, "%s up\n", valid ? "pt" : "unused pt"); + if (!valid) + break; + input_mt_sync(idev); + break; + case SYN_FUNCAREA_BUTTON: + LOG_EVENT(this, "button up\n"); + button = (struct clearpad_button_data_t *) + pointer->funcarea->data; + if (button) + button->down = false; + break; + default: + break; + } + pointer->funcarea = NULL; +} + +static void clearpad_funcarea_out(struct clearpad_t *this, + struct clearpad_pointer_t *pointer) +{ + struct clearpad_funcarea_t *new_funcarea; + + clearpad_funcarea_up(this, pointer); + + new_funcarea = clearpad_funcarea_search(this, pointer); + if (new_funcarea == NULL) + return; + + switch (new_funcarea->func) { + case SYN_FUNCAREA_INSENSIBLE: + pointer->down = false; + break; + default: + break; + } +} + +static void clearpad_report_button(struct clearpad_t *this, + struct clearpad_button_data_t *button) +{ + bool valid = this->input->users > 0; + + if (button->down) { + if (!button->down_report) { + button->down_report = true; + if (valid) + input_report_key(this->input, button->code, 1); + LOG_EVENT(this, "%s(%d): down\n", + valid ? "key" : "unused key", button->code); + } + } else { + if (button->down_report) { + button->down_report = false; + if (valid) + input_report_key(this->input, button->code, 0); + LOG_EVENT(this, "%s(%d): up\n", + valid ? "key" : "unused key", button->code); + } + } +} + +static void +clearpad_funcarea_report_extra_events(struct clearpad_t *this) +{ + struct clearpad_funcarea_t *funcarea = this->funcarea; + struct clearpad_button_data_t *button; + + if (funcarea == NULL) + return; + + for (; funcarea->func != SYN_FUNCAREA_END; funcarea++) { + if (funcarea->func == SYN_FUNCAREA_BUTTON) { + button = + (struct clearpad_button_data_t *)funcarea->data; + if (button) + clearpad_report_button(this, button); + } + } +} + +static void clearpad_funcarea_invalidate_all(struct clearpad_t *this) +{ + struct clearpad_pointer_t *pointer; + int i; + + for (i = 0; i < this->extents.n_fingers; ++i) { + pointer = &this->pointer[i]; + if (pointer->down) { + pointer->down = false; + LOG_VERBOSE(this, "invalidate pointer %d\n", i); + } + if (pointer->funcarea) + clearpad_funcarea_up(this, pointer); + } + clearpad_funcarea_report_extra_events(this); + if (this->input->users) + input_sync(this->input); +} + +static void clearpad_parse_finger_n_f12(struct clearpad_t *this, + const u8 *buf, int finger, struct clearpad_point_t *new_point) +{ + enum registers { + REG_TYPE_STATUS, + REG_X_LSB, + REG_X_MSB, + REG_Y_LSB, + REG_Y_MSB, + REG_Z, + REG_WX, + REG_WY, + }; + buf += this->extents.n_bytes_per_object * finger; + new_point->tool = buf[REG_TYPE_STATUS]; + new_point->tool = clearpad_tool_type_f12[new_point->tool]; + new_point->id = finger; + new_point->x = (buf[REG_X_MSB] << 8) | buf[REG_X_LSB]; + new_point->y = (buf[REG_Y_MSB] << 8) | buf[REG_Y_LSB]; + new_point->wx = buf[REG_WX]; + new_point->wy = buf[REG_WY]; + new_point->z = buf[REG_Z]; +} + +static void clearpad_report_finger_n(struct clearpad_t *this, + const u8 *buf, int finger) +{ + struct clearpad_pointer_t *pointer = &this->pointer[finger]; + struct clearpad_point_t new_point; + struct clearpad_area_t *extension; + + if (clearpad_is_valid_function(this, SYN_F12_2D)) + clearpad_parse_finger_n_f12(this, buf, finger, &new_point); + else + return; + + /* check finger state */ + if (new_point.tool == SYN_TOOL_FINGER || + (this->glove.enabled && new_point.tool == SYN_TOOL_GLOVE) || + (this->pen.enabled && (new_point.tool == SYN_TOOL_PEN))) { + + switch (this->flip_config) { + case SYN_FLIP_X: + new_point.x = this->extents.x_max - new_point.x; + break; + case SYN_FLIP_Y: + new_point.y = this->extents.y_max - new_point.y; + break; + case SYN_FLIP_XY: + new_point.x = this->extents.x_max - new_point.x; + new_point.y = this->extents.y_max - new_point.y; + break; + case SYN_FLIP_NONE: + default: + break; + } + + LOG_VERBOSE(this, "pt[%d]: (x,y)=(%d,%d) w=(%d,%d) z=%d t=%d\n", + new_point.id, new_point.x, new_point.y, + new_point.wx, new_point.wy, new_point.z, + new_point.tool); + + if (!pointer->down) { + if (clearpad_funcarea_test(&this->funcarea->original, &new_point)) { + /* first touch event */ + pointer->down = true; + pointer->cur = new_point; + pointer->funcarea + = clearpad_funcarea_search(this, pointer); + LOG_VERBOSE(this, "validate pointer %d [func %d]\n", + new_point.id, pointer->funcarea + ? pointer->funcarea->func : -1); + } else { + LOGW(this, "invalidate pointer %d\n", new_point.id); + } + } + if (pointer->funcarea) { + extension = &pointer->funcarea->extension; + + if (clearpad_funcarea_test(extension, &new_point)) { + pointer->cur = new_point; + clearpad_funcarea_down(this, pointer); + } else { + pointer->down = false; + clearpad_funcarea_out(this, pointer); + LOGW(this, "invalidate pointer %d\n", new_point.id); + } + } + } else { + if (pointer->down) { + pointer->down = false; + LOG_VERBOSE(this, "invalidate pointer %d\n", finger); + } + if (pointer->funcarea) + clearpad_funcarea_up(this, pointer); + } +} + +static int get_num_fingers_f12(struct clearpad_t *this, + int *num_fingers) +{ + int rc, num; + u16 val, mask; + const int max_objects = this->extents.n_fingers; + + /* F12_2D_DATA15: Object Attention */ + rc = clearpad_get_block(SYNA(this, F12_2D, DATA, 15), + (u8 *)&val, sizeof(val)); + if (rc) + goto end; + + val = le16_to_cpu(val); + + for (num = 0, mask = 0x1; num < max_objects; num++, mask <<= 1) + if (val < mask) + break; + + *num_fingers = num; + + LOG_CHECK(this, "fingers=%d, 0x%04hX", num, val); +end: + return rc; +} + +static int clearpad_read_fingers_f12(struct clearpad_t *this) +{ + int rc, finger, num_fingers; + u8 buf[this->extents.n_fingers * this->extents.n_bytes_per_object]; + + memset(buf, 0, sizeof(buf)); + + rc = get_num_fingers_f12(this, &num_fingers); + if (rc) + goto end; + + if (num_fingers > 0) { + /* F12_2D_DATA01: Sensed Objects */ + rc = clearpad_get_block(SYNA(this, F12_2D, DATA, 1), + buf, num_fingers * this->extents.n_bytes_per_object); + if (rc) + goto end; + } + + for (finger = 0; finger < this->extents.n_fingers; finger++) + clearpad_report_finger_n(this, buf, finger); +end: + return rc; +} + +static int clearpad_handle_gesture(struct clearpad_t *this) +{ + u8 wakeint = 0; + int rc = -EIO; + + if (clearpad_is_valid_function(this, SYN_F12_2D)) + /* F12_2D_DATA04: Detected Gestures */ + rc = clearpad_get(SYNA(this, F12_2D, DATA, 0x04), &wakeint); + if (rc) + goto end; + + LOGI(this, "gesture: %d\n", wakeint); + + if (time_after(jiffies, this->wakeup_gesture.time_started)) + this->wakeup_gesture.time_started = jiffies + + msecs_to_jiffies(this->wakeup_gesture.timeout_delay); + else + goto end; + + evdt_execute(this->evdt_node, this->input, wakeint); +end: + return rc; +} + +static int clearpad_process_F01_RMI(struct clearpad_t *this, u8 device_status) +{ + int rc = 0; + + HWLOGI(this, "device status 0x%02x (code=%d, unconfig=%d)\n", + device_status, BIT_GET(device_status, DEVICE_STATUS_CODE), + BIT_GET(device_status, DEVICE_STATUS_UNCONFIGURED)); + if (BIT_GET(device_status, DEVICE_STATUS_CODE) + == DEVICE_STATUS_CODE_RESET_OCCURRED && + BIT_GET(device_status, DEVICE_STATUS_UNCONFIGURED)) { + LOGI(this, "device reset\n"); + /* initialized already */ + WARN_ON(this->interrupt.count != 0); + /* check result of flash disabling */ + WARN_ON(BIT_GET(device_status, DEVICE_STATUS_FLASH_PROG)); + HWLOGI(this, "clear glitch (irq_pending=%s) for reset\n", + this->irq_pending ? "true" : "false"); + + if (this->force_sleep == FSMODE_ONESHOT) { + LOGI(this, "clear force sleep mode\n"); + this->force_sleep = FSMODE_OFF; + } + if (this->force_sleep != FSMODE_OFF) { + HWLOGI(this, "force sleep mode\n"); + if (this->dev_active) { + rc = clearpad_set_suspend_mode(this); + if (rc) + HWLOGE(this, "failed to suspend " + "(rc=%d)\n", rc); + } + } else if (!this->dev_active) { + rc = clearpad_set_resume_mode(this); + if (rc) + HWLOGE(this, "failed to resume (rc=%d)\n", rc); + } + clearpad_notify_interrupt(this, &this->interrupt.for_reset, 0); + } else if (BIT_GET(device_status, DEVICE_STATUS_CODE) + == DEVICE_STATUS_CODE_DEVICE_FAILURE) { + clearpad_reset(this, SYN_HWRESET, __func__); + } else { + LOGI(this, "unexpected device status=0x%02x\n", device_status); + } + return rc; +} + +static int clearpad_process_F12_2D(struct clearpad_t *this, bool *waked) +{ + int rc = 0; + u8 status; + + *waked = false; + + if (!this->post_probe.done) { + LOGI(this, "ignore event before end of post probe\n"); + goto end; + } + + if (this->wakeup_gesture.enabled && !this->dev_active && + !this->last_irq) { + rc = clearpad_handle_gesture(this); + if (!rc) + *waked = true; + goto end; + } + + /* F01_RMI_DATA00: Device Status */ + rc = clearpad_get(SYNF(this, F01_RMI, DATA, + this->reg_offset.f01_data00), &status); + LOG_CHECK(this, "rc=%d F01_RMI_DATA00=0x%x\n", rc, status); + if (rc) + goto end; + + if (BIT_GET(status, DEVICE_STATUS_CODE) + == DEVICE_STATUS_CODE_DEVICE_FAILURE) { + LOGE(this, "found device failure\n"); + WARN_ON(1); /* instead of HWRESET */ + goto end; + } + + rc = clearpad_read_fingers_f12(this); + if (rc) + goto end; + if (this->input->users) + input_sync(this->input); +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_process_irq(struct clearpad_t *this) +{ + int rc = 0; + u8 interrupt_status = 0; + u8 device_status = 0; + bool waked = false; + unsigned long flags; + + if (this->flash.enter_bootloader_mode) { + clearpad_set_delay(this->reset.delay_for_powerup_ms); + this->flash.enter_bootloader_mode = false; + HWLOGI(this, "clear glitch (irq_pending=%s) " + "for entering bootloader mode\n", + this->irq_pending ? "true" : "false"); + spin_lock_irqsave(&this->slock, flags); + this->irq_pending = false; + spin_unlock_irqrestore(&this->slock, flags); + } + if (clearpad_initialize_if_first_event(this, + &interrupt_status, &device_status) < 0) { + LOGE(this, "failed to initialize for first event\n"); + rc = -EBUSY; + goto no_valid_interrupt; + } + + if (interrupt_status & this->pdt[SYN_F34_FLASH].irq_mask) { + if (this->flash.fw) + clearpad_flash(this); + clearpad_notify_interrupt(this, &this->interrupt.for_F34, 0); + } else if (interrupt_status & this->pdt[SYN_F01_RMI].irq_mask) { + rc = clearpad_process_F01_RMI(this, device_status); + } else if (interrupt_status & this->pdt[SYN_F54_ANALOG].irq_mask) { + this->state = SYN_STATE_RUNNING; + clearpad_notify_interrupt(this, &this->interrupt.for_F54, 0); + } else if (interrupt_status & this->pdt[SYN_F12_2D].irq_mask) { + rc = clearpad_process_F12_2D(this, &waked); + if (!rc && waked) { + /* will resume in next first event */ + this->interrupt.count = 0; + goto no_valid_interrupt; + } + } else { + LOGI(this, "no work, interrupt=[0x%02x]\n", interrupt_status); + } + + if (this->interrupt.count == 0 && rc) + goto no_valid_interrupt; + + this->interrupt.count += 1; + if (this->interrupt.count == 0) { + LOGI(this, "rewind interrupt.count\n"); + this->interrupt.count = 1; + } + +no_valid_interrupt: + if (rc) { + LOGE(this, "error (icount=%u rc=%d)\n", + this->interrupt.count, rc); + WARN_ON(1); /* instead of HWRESET */ + } + + if (this->watchdog.enabled) + clearpad_watchdog_update(this); + + return rc; +} + +/* need LOCK(&this->lock) */ +static bool clearpad_process_noise_det_irq(struct clearpad_t *this) +{ + bool retry = false; + int rc = 0; + + if (!this->post_probe.done) { + LOGW(this, "post_probe hasn't finished, not need to retry\n"); + goto not_done_post_probe; + } + + if (this->touchctrl.will_powerdown) { + LOGW(this, "will_powerdown, not need to retry\n"); + goto will_powerdown; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "not read I2C access, need to retry\n"); + retry = true; + goto not_ready_to_access_i2c; + } + + if (!touchctrl_lock_power(this, "noise_det_irq", true, false)) { + HWLOGW(this, "power is already turned off, need to retry\n"); + retry = true; + goto end; + } + + /* F01_RMI_CTRL18: Device Control 1 */ + rc = clearpad_put_bit( + SYNF(this, F01_RMI, CTRL, this->reg_offset.f01_ctrl18), + DEVICE_CONTROL_1_GSM_ENABLE_MASK, + DEVICE_CONTROL_1_GSM_ENABLE_MASK); + if (rc) { + LOGE(this, "failed to set noise reduction bit\n"); + retry = true; + goto err_i2c_access; + } + +err_i2c_access: + touchctrl_unlock_power(this, "noise_det_irq"); + +not_done_post_probe: +will_powerdown: +not_ready_to_access_i2c: +end: + return retry; +} + +static irqreturn_t clearpad_threaded_handler(int irq, void *dev_id) +{ + struct clearpad_t *this = dev_id; + unsigned long flags; + bool locked; + + get_monotonic_boottime(&this->interrupt.threaded_handler_ts); + + LOCK(&this->lock); + locked = touchctrl_lock_power(this, "irq_handler", true, false); + /* workaround to clear interrupt status */ + if (!locked) + HWLOGW(this, "read interrupt status though no power lock\n"); + + do { + (void)clearpad_process_irq(this); + + spin_lock_irqsave(&this->slock, flags); + if (likely(!this->irq_pending)) { + this->dev_busy = false; + spin_unlock_irqrestore(&this->slock, flags); + break; + } + this->irq_pending = false; + spin_unlock_irqrestore(&this->slock, flags); + LOGD(this, "touch irq pending\n"); + } while (true); + + if (locked) + touchctrl_unlock_power(this, "irq_handler"); + UNLOCK(&this->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t clearpad_hard_handler(int irq, void *dev_id) +{ + struct clearpad_t *this = dev_id; + unsigned long flags; + irqreturn_t ret; + + get_monotonic_boottime(&this->interrupt.hard_handler_ts); + + spin_lock_irqsave(&this->slock, flags); + if (unlikely(this->dev_busy)) { + this->irq_pending = true; + ret = IRQ_HANDLED; + } else { + this->dev_busy = true; + ret = IRQ_WAKE_THREAD; + } + spin_unlock_irqrestore(&this->slock, flags); + if (ret == IRQ_HANDLED) + LOGD(this, "touch irq busy\n"); + return ret; +} + +static irqreturn_t clearpad_noise_det_threaded_handler(int irq, void *dev_id) +{ + struct clearpad_t *this = dev_id; + bool retry = false; + + get_monotonic_boottime(&this->noise_det.threaded_handler_ts); + LOCK(&this->lock); + + retry = clearpad_process_noise_det_irq(this); + + this->noise_det.threaded_handler_count += 1; + if (this->noise_det.threaded_handler_count == 0) { + LOGI(this, "rewind noise_det.threaded_handler_count\n"); + this->noise_det.threaded_handler_count = 1; + } + UNLOCK(&this->lock); + + if (retry) { + clearpad_set_delay(this->noise_det.retry_time_ms); + LOGI(this, "Enable det_irq for retry hic=%u tic=%u@ " + "@ %ld.%06ld\n", + this->noise_det.hard_handler_count, + this->noise_det.threaded_handler_count, + this->noise_det.threaded_handler_ts.tv_sec, + this->noise_det.threaded_handler_ts.tv_nsec); + if (clearpad_set_noise_det_irq(this, true, true)) + HWLOGE(this, "no noise_det irq change (enable)\n"); + else + LOGI(this, "noise_det irq was enabled\n"); + } else { + LOGI(this, "Success set fw_bit hic=%u tic=%u@ %ld.%06ld\n", + this->noise_det.hard_handler_count, + this->noise_det.threaded_handler_count, + this->noise_det.threaded_handler_ts.tv_sec, + this->noise_det.threaded_handler_ts.tv_nsec); + } + return IRQ_HANDLED; +} + +static irqreturn_t clearpad_noise_det_hard_handler(int irq, void *dev_id) +{ + struct clearpad_t *this = dev_id; + irqreturn_t ret; + unsigned long flags; + + get_monotonic_boottime(&this->noise_det.hard_handler_ts); + if (clearpad_set_noise_det_irq(this, false, false)) + HWLOGE(this, "no noise_det irq change(disable)\n"); + else + LOGD(this, "noise_det irq was disabled\n"); + + spin_lock_irqsave(&this->noise_det.slock, flags); + if (this->noise_det.first_irq) { + this->noise_det.first_irq = false; + ret = IRQ_HANDLED; + } else { + ret = IRQ_WAKE_THREAD; + } + this->noise_det.hard_handler_count += 1; + if (this->noise_det.hard_handler_count == 0) { + LOGI(this, "rewind hard_handler_count.th_handler_count\n"); + this->noise_det.hard_handler_count = 1; + } + spin_unlock_irqrestore(&this->noise_det.slock, flags); + + if (ret == IRQ_HANDLED) { + if (clearpad_set_noise_det_irq(this, true, false)) + HWLOGE(this, "no noise_det irq change" + " w/o 1st_irq(enable)\n"); + else + LOGD(this, "noise_det irq was enabled w/o 1st_irq\n"); + } else { + LOGD(this, "Wake up noise_det_threaded_handle hic=%u tic=%u " + "@ %ld.%06ld\n", + this->noise_det.hard_handler_count, + this->noise_det.threaded_handler_count, + this->noise_det.hard_handler_ts.tv_sec, + this->noise_det.hard_handler_ts.tv_nsec); + } + return ret; +} + +static int clearpad_device_open(struct input_dev *dev) +{ + struct clearpad_t *this = input_get_drvdata(dev); + int rc; + + LOG_STAT(this, "state=%s\n", NAME_OF(clearpad_state_name, this->state)); + + switch (this->state) { + case SYN_STATE_INIT: + rc = 0; + break; + case SYN_STATE_DISABLED: + rc = -ENODEV; + break; + case SYN_STATE_RUNNING: + rc = this->post_probe.done ? 0 : -ENODEV; + break; + default: + rc = -EBUSY; + break; + } + + return rc; +} + +static void clearpad_device_close(struct input_dev *dev) +{ + struct clearpad_t *this = input_get_drvdata(dev); + + LOCK(&this->lock); + LOG_STAT(this, "state=%s\n", NAME_OF(clearpad_state_name, this->state)); + + UNLOCK(&this->lock); +} + +/* need LOCK(&this->lock) */ +static int clearpad_command_fwflash(struct clearpad_t *this) +{ + struct clearpad_device_info_t *info = &this->device_info; + int rc; + + memset(this->result_info, 0, SYN_STRING_LENGTH); + this->flash_requested = true; + this->reg_offset.updated = false; + + /* prepare to waiting for end of flash */ + clearpad_prepare_for_interrupt(this, &this->interrupt.for_reset, + "wait for flashing"); + + if (this->flash.fw) { + HWLOGI(this, "start firmware flash\n"); + this->flash.analog_id = info->analog_id; + this->state = SYN_STATE_FLASH_IMAGE_SET; + rc = clearpad_flash(this); + LOG_CHECK(this, "rc=%d\n", rc); + if (rc) { + clearpad_undo_prepared_interrupt(this, + &this->interrupt.for_reset, "wait for flashing"); + goto error; + } + } + + /* wait for end of flash */ + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, &this->interrupt.for_reset, + this->flash.default_timeout_ms); + LOCK(&this->lock); + if (rc) { + LOGE(this, "failed to get interrupt (rc=%d)\n", rc); + goto error; + } + +error: + snprintf(this->result_info, SYN_STRING_LENGTH, + "%s, family 0x%02x, fw rev 0x%02x.%02x, extra 0x%02x, %s\n", + clearpad_s(this->device_info.product_id, + HEADER_PRODUCT_ID_SIZE), + this->device_info.customer_family, + this->device_info.firmware_revision_major, + this->device_info.firmware_revision_minor, + this->device_info.firmware_revision_extra, + rc == 0 ? "succeeded fw update" : "failed fw update"); + this->flash_requested = false; + HWLOGI(this, "result: %s", this->result_info); + + if (this->watchdog.enabled) + clearpad_watchdog_update(this); + + if (rc) { + /* inform disabled state */ + this->state = SYN_STATE_DISABLED; + clearpad_reset(this, SYN_SWRESET, __func__); + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_reset, + this->flash.default_timeout_ms); + LOCK(&this->lock); + if (rc) + LOGE(this, "failed to get interrupt (rc=%d)\n", rc); + } + return rc; +} + +static ssize_t clearpad_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct clearpad_t *this = dev_get_drvdata(dev); + struct clearpad_touchctrl_t *touchctrl = &this->touchctrl; + + if (!strncmp(attr->attr.name, __stringify(post_probe_start), + PAGE_SIZE)) { + snprintf(buf, PAGE_SIZE, + "%d", this->post_probe.start); + goto end; + } + + if (!this->post_probe.done) { + LOGW(this, "post_probe hasn't finished, please retry later\n"); + buf[0] = '\0'; + goto end; + } + + if (!strncmp(attr->attr.name, __stringify(fwinfo), PAGE_SIZE)) { + snprintf(buf, PAGE_SIZE, + "%s, family 0x%02x, fw rev 0x%02x.%02x, " + "extra 0x%02x, aid 0x%02x, state=%s, " + "active=%s, type=%s, icount=%u, session=%s, " + "power(touch=%s display=%s user=%d)\n", + clearpad_s(this->device_info.product_id, + HEADER_PRODUCT_ID_SIZE), + this->device_info.customer_family, + this->device_info.firmware_revision_major, + this->device_info.firmware_revision_minor, + this->device_info.firmware_revision_extra, + this->device_info.analog_id, + NAME_OF(clearpad_state_name, this->state), + this->dev_active ? "true" : "false", + NAME_OF(clearpad_chip_name, this->chip_id), + this->interrupt.count, touchctrl->session, + touchctrl_is_touch_powered(this) ? "OK" : "NG", + touchctrl_is_display_powered(this) ? "OK" : "NG", + touchctrl->power_user); + } else if (!strncmp(attr->attr.name, __stringify(fwchip_id), PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%x", this->chip_id); + else if (!strncmp(attr->attr.name, __stringify(fwfamily), PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%x", this->device_info.customer_family); + else if (!strncmp(attr->attr.name, __stringify(fwrevision), PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%x", this->device_info.firmware_revision_major); + else if (!strncmp(attr->attr.name, + __stringify(fwrevision_minor), PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%x", this->device_info.firmware_revision_minor); + else if (!strncmp(attr->attr.name, + __stringify(fwrevision_extra), PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%x", this->device_info.firmware_revision_extra); + else if (!strncmp(attr->attr.name, __stringify(fwstate), PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, "%s", + NAME_OF(clearpad_state_name, this->state)); + else if (!strncmp(attr->attr.name, __stringify(wakeup_gesture), + PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, "%d", + this->wakeup_gesture.enabled); + else if (!strncmp(attr->attr.name, __stringify(pen), PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->pen.enabled); + else if (!strncmp(attr->attr.name, __stringify(glove), PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->glove.enabled); + else if (!strncmp(attr->attr.name, __stringify(force_sleep), PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->force_sleep); + else if (!strncmp(attr->attr.name, __stringify(charger_status), + PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->charger.status); + else if (!strncmp(attr->attr.name, __stringify(cover_status), + PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->cover.status); + else if (!strncmp(attr->attr.name, __stringify(cover_mode_enabled), + PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->cover.enabled); + else if (!strncmp(attr->attr.name, __stringify(cover_win_top), + PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->cover.win_top); + else if (!strncmp(attr->attr.name, __stringify(cover_win_bottom), + PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->cover.win_bottom); + else if (!strncmp(attr->attr.name, __stringify(cover_win_right), + PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->cover.win_right); + else if (!strncmp(attr->attr.name, __stringify(cover_win_left), + PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->cover.win_left); + else if (!strncmp(attr->attr.name, __stringify(stamina_mode), + PAGE_SIZE)) + snprintf(buf, PAGE_SIZE, + "%d", this->stamina.enabled); + else + snprintf(buf, PAGE_SIZE, "illegal sysfs file"); +end: + return strnlen(buf, PAGE_SIZE); +} + +/* + * Calibration + */ + +/* need LOCK(&this->lock) */ +static int clearpad_do_calibration(struct clearpad_t *this, int mode, + u8 calibration_crc) +{ + unsigned long timeout; + int rc = 0; + int reset_rc = 0; + bool calibrate; + u8 status, bit, need_bit; + + switch (mode) { + case SYN_CALIBRATION_NORMAL: + need_bit = CALIBRATION_STATE_CALIBRATION_CRC_MASK; + calibrate = !!BIT_GET(calibration_crc, + CALIBRATION_STATE_CALIBRATION_CRC); + bit = START_CAL_PROD_TEST_START_CALIBRATION_MASK; + timeout = jiffies + msecs_to_jiffies(SYN_CALIBRATION_WAIT_MS); + break; + case SYN_CALIBRATION_EW: + need_bit = CALIBRATION_STATE_IS_CALIBRATION_CRC_MASK; + calibrate = !!BIT_GET(calibration_crc, + CALIBRATION_STATE_IS_CALIBRATION_CRC); + if (!calibrate) + break; + /* make display sleep state */ + touchctrl_notify_wakeup_gesture_mode(this, true); + rc = touchctrl_display_off(this); + if (rc) { + LOGE(this, "failed to turn display off\n"); + calibrate = false; + break; + } + /* set correct state after powerdown */ + touchctrl_notify_wakeup_gesture_mode(this, + this->wakeup_gesture.enabled); + + bit = START_CAL_PROD_TEST_START_IS_CALIBRATION_MASK; + timeout = jiffies + + msecs_to_jiffies(SYN_CALIBRATION_EW_WAIT_MS); + break; + default: + HWLOGI(this, "unknown mode %d\n", mode); + rc = -EINVAL; + goto end; + } + HWLOGI(this, "%s : %s\n", NAME_OF(clearpad_calibration_name, mode), + calibrate ? "Start" : "Skip"); + if (!calibrate) + goto end; + + clearpad_set_delay(SYN_CALIBRATION_SETUP_TIME); + /* start calibration */ + /* F54_ANALOG_CTRL188: Start Calibration or Production Test */ + rc = clearpad_put_bit(SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl188), bit, bit); + if (rc) { + HWLOGE(this, "failed to start %s\n", + NAME_OF(clearpad_calibration_name, mode)); + goto end; + } + + /* wait until end of calibration */ + do { + clearpad_set_delay(SYN_CALIBRATION_WAIT); + /* F54_ANALOG_CTRL188: Start Calibration or Production Test */ + rc = clearpad_get(SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl188), + &status); + if (rc) + HWLOGE(this, "failed to read status\n"); + if (!(status & bit)) + goto succeeded; + } while (time_before(jiffies, timeout)); + HWLOGE(this, "calibration time out\n"); + rc = -EIO; + goto end; + +succeeded: + rc = clearpad_get(SYNF(this, F54_ANALOG, DATA, + this->reg_offset.f54_data31), &status); + if (rc) { + HWLOGE(this, "failed to get calibration status\n"); + goto end; + } + /* check calibration result */ + if (status & need_bit) { + HWLOGE(this, "%s was failed, crc = %x\n", + NAME_OF(clearpad_calibration_name, mode), status); + rc = -EIO; + } + HWLOGI(this, "%s : %s\n", NAME_OF(clearpad_calibration_name, mode), + status & need_bit ? "Failed" : "Succeed"); + + clearpad_set_delay(20); + +end: + switch (mode) { + case SYN_CALIBRATION_EW: + if (!calibrate) + break; + clearpad_set_delay(SYN_CALIBRATION_BEFORE_HWRESET_WAIT); + clearpad_reset(this, SYN_HWRESET, "Calibration(EW)"); + UNLOCK(&this->lock); + reset_rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_reset, + this->interrupt.wait_ms); + LOCK(&this->lock); + if (reset_rc) + LOGE(this, "failed to get interrupt (rc=%d)\n", rc); + break; + default: + break; + } + + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_calibrate_on_fwflash(struct clearpad_t *this, + bool fwflashed) +{ + struct clearpad_device_info_t *info = &this->device_info; + int rc, i; + u8 calibration_crc = 0; + + if (!clearpad_is_valid_function(this, SYN_F54_ANALOG)) { + rc = -EIO; + HWLOGE(this, "F54_ANALOG invalid\n"); + goto end; + } + + HWLOGI(this, "old aid = %x, new aid = %x\n", + this->flash.analog_id, info->analog_id); + /* check if needed */ + if (fwflashed && (this->flash.analog_id != info->analog_id)) { + HWLOGW(this, "analog ID is not matching\n"); + BIT_SET(calibration_crc, + CALIBRATION_STATE_CALIBRATION_CRC, 1); + BIT_SET(calibration_crc, + CALIBRATION_STATE_IS_CALIBRATION_CRC, 1); + } else { + rc = clearpad_get(SYNF(this, F54_ANALOG, DATA, + this->reg_offset.f54_data31), + &calibration_crc); + if (rc) { + HWLOGE(this, "failed to get calibration status\n"); + goto end; + } + } + + for (i = 0; i < 2; i++) { + rc = clearpad_do_calibration(this, SYN_CALIBRATION_NORMAL, + calibration_crc); + if (rc) { + LOGE(this, "failed normal calibration\n"); + if (i > 0) + goto end; + clearpad_reset(this, SYN_SWRESET, __func__); + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_reset, + this->interrupt.wait_ms); + LOCK(&this->lock); + if (rc) + LOGE(this, "failed to get interrupt (rc=%d)\n", + rc); + continue; + } + break; + } + + rc = clearpad_do_calibration(this, SYN_CALIBRATION_EW, calibration_crc); + if (rc) + LOGE(this, "failed ew calibration\n"); + +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_fwflash_core(struct clearpad_t *this, + enum clearpad_flash_command_e command, + unsigned int id) +{ + struct clearpad_flash_t *flash = &this->flash; + int rc; + bool do_update = false; + + if (!this->dev_active) { + rc = -EINVAL; + HWLOGW(this, "could not start fwflash because " + "device is in suspended mode\n"); + goto err_in_device_mode; + } + + if (this->flash.fw) { + rc = -EAGAIN; + HWLOGE(this, "previous fw update is ongoing\n"); + goto err_in_busy_check; + } + clearpad_firmware_reset(this); + flash->command = command; + + rc = clearpad_judge_firmware_flash(this, id, command); + if (rc < 0) + goto err_in_judgement; + + do_update = (rc == 1) ? true : false; + if (do_update) { + /* enable irq inside flash_enable */ + rc = clearpad_command_fwflash(this); + if (rc) { + HWLOGE(this, "firmware flash was failed\n"); + goto err_in_fw_flash; + } + } + + if (this->calibration_supported && this->calibrate_on_fwflash) { + rc = clearpad_calibrate_on_fwflash(this, do_update); + if (rc) { + HWLOGE(this, "calibrate fatal error\n"); + goto err_in_calibration; + } + } + +err_in_calibration: +err_in_fw_flash: +err_in_judgement: + clearpad_firmware_reset(this); +err_in_busy_check: +err_in_device_mode: + return rc; +} + +static ssize_t clearpad_fwflash_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct clearpad_t *this = dev_get_drvdata(dev); + const char **command = (const char **)clearpad_flash_command_name; + const char *session = "fwflash store"; + int rc = 0; + unsigned int id = 0; + char request[SYN_STRING_LENGTH] = ""; + + if (!this->post_probe.done) { + LOGW(this, "post_probe hasn't finished, please retry later\n"); + goto err_in_check_post_probe; + } + + HWLOGI(this, "flash command: %s\n", buf); + if (sscanf(buf, "%7s %4x", request, &id) < 0) { + HWLOGE(this, "%s sscanf failed ", buf); + rc = -EINVAL; + goto err_in_fw_flash_command_check; + } + HWLOGI(this, "request: %s\n", request); + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) + goto err_in_ctrl_begin; + + LOCK(&this->lock); + if (!strncmp(request, command[SYN_FORCE_FLASH], PAGE_SIZE)) { + HWLOGI(this, "start force firmware flash, id=%x\n", id); + rc = clearpad_fwflash_core(this, SYN_FORCE_FLASH, id); + } else if (!strncmp(request, command[SYN_DEFAULT_FLASH], PAGE_SIZE)) { + HWLOGI(this, "start firmware config & data\n"); + rc = clearpad_fwflash_core(this, SYN_DEFAULT_FLASH, 0); + } else { + HWLOGE(this, "illegal command\n"); + rc = -EINVAL; + } + UNLOCK(&this->lock); + + clearpad_ctrl_session_end(this, session); + +err_in_ctrl_begin: +err_in_fw_flash_command_check: +err_in_check_post_probe: + return rc ? rc : size; +} + +static ssize_t clearpad_enabled_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct clearpad_t *this = dev_get_drvdata(dev); + int rc = 0; + + LOGD(this, "start\n"); + + if (!this->post_probe.done) { + LOGW(this, "post_probe hasn't finished, please retry later\n"); + goto err_in_check_post_probe; + } + + LOCK(&this->lock); + + if (sysfs_streq(buf, "1")) { + rc = clearpad_gpio_export(this, &this->input->dev, + false); + if (rc) + LOGE(this, "failed to unexport gpio\n"); + goto enable; + } else if (sysfs_streq(buf, "0")) { + devm_free_irq(&this->pdev->dev, this->irq, this); + if (this->noise_det.supported) + devm_free_irq(&this->pdev->dev, + this->noise_det.irq, this); + rc = clearpad_gpio_export(this, &this->input->dev, + true); + if (rc) { + LOGE(this, "failed to export gpio\n"); + goto enable; + } + } + goto end; + +enable: + rc = devm_request_threaded_irq(&this->pdev->dev, + this->irq, + clearpad_hard_handler, + clearpad_threaded_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + this->pdev->dev.driver->name, this); + if (rc) + LOGE(this, "irq %d busy? <%d>\n", this->irq, rc); + + if (this->noise_det.supported) { + rc = devm_request_threaded_irq(&this->pdev->dev, + this->noise_det.irq, + clearpad_noise_det_hard_handler, + clearpad_noise_det_threaded_handler, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "clearpad_noise_det", this); + if (rc) + LOGE(this, "noise_det irq %d busy? <%d>\n", + this->noise_det.irq, rc); + } +end: + UNLOCK(&this->lock); + +err_in_check_post_probe: + LOG_STAT(this, "state=%s\n", NAME_OF(clearpad_state_name, this->state)); + return strnlen(buf, PAGE_SIZE); +} + +static ssize_t clearpad_glove_enabled_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct clearpad_t *this = dev_get_drvdata(dev); + const char *session = "glove enabled store"; + int rc = 0; + bool lazy_update = false; + + LOGD(this, "start\n"); + + if (!this->glove.supported) { + LOGI(this, "glove mode is not supported"); + goto err_in_check_support; + } + + if (!this->post_probe.done) { + LOGI(this, "post_probe hasn't finished, will apply later\n"); + lazy_update = true; + goto err_in_check_post_probe; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + lazy_update = true; + goto not_ready_to_access_i2c; + } + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + LOGI(this, "not powered, will be applied later\n"); + lazy_update = true; + goto err_in_session_begin; + } + +err_in_session_begin: +not_ready_to_access_i2c: +err_in_check_post_probe: + LOCK(&this->lock); + this->glove.enabled = sysfs_streq(buf, "0") ? false : true; + if (!lazy_update) { + rc = clearpad_set_glove_mode(this, this->glove.enabled); + if (rc) + LOGE(this, "failed to set glove for device\n"); + } + LOGI(this, "glove mode: %s", + this->glove.enabled ? "ENABLE" : "DISABLE"); + UNLOCK(&this->lock); + + if (!lazy_update) + clearpad_ctrl_session_end(this, session); + +err_in_check_support: + return size; +} + +static ssize_t clearpad_pen_enabled_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct clearpad_t *this = dev_get_drvdata(dev); + const char *session = "pen enabled store"; + int rc = 0; + bool lazy_update = false; + + LOGD(this, "start\n"); + + if (!this->pen.supported) { + LOGI(this, "pen is not supported"); + goto err_in_check_support; + } + + if (!this->post_probe.done) { + LOGI(this, "post_probe hasn't finished, will apply later\n"); + lazy_update = true; + goto err_in_check_post_probe; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + lazy_update = true; + goto not_ready_to_access_i2c; + } + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + LOGI(this, "not powered, will be applied later\n"); + lazy_update = true; + goto err_in_session_begin; + } + +err_in_session_begin: +not_ready_to_access_i2c: +err_in_check_post_probe: + LOCK(&this->lock); + this->pen.enabled = sysfs_streq(buf, "0") ? false : true; + if (!lazy_update) { + rc = clearpad_set_pen(this); + if (rc) + LOGE(this, "failed to set pen for device\n"); + } + LOGI(this, "pen mode: %s", this->pen.enabled ? "ENABLE" : "DISABLE"); + UNLOCK(&this->lock); + + if (!lazy_update) + clearpad_ctrl_session_end(this, session); + +err_in_check_support: + return size; +} + +static ssize_t clearpad_wakeup_gesture_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int rc = 0; + const char *session = "wakeup gesture store"; + struct clearpad_t *this = dev_get_drvdata(dev); + bool new = false; + bool old; + bool lazy_update = false; + + LOGD(this, "start\n"); + + if (!this->wakeup_gesture.supported) { + LOGI(this, "wakeup gesture is not supported"); + goto err_in_check_support; + } + + if (!this->post_probe.done) { + LOGI(this, "post_probe hasn't finished, will apply later\n"); + lazy_update = true; + goto err_in_check_post_probe; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + lazy_update = true; + goto not_ready_to_access_i2c; + } + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + LOGI(this, "not powered, will be applied later\n"); + lazy_update = true; + goto err_in_session_begin; + + } + +err_in_session_begin: +not_ready_to_access_i2c: +err_in_check_post_probe: + LOCK(&this->lock); + new = sysfs_streq(buf, "0") ? false : true; + old = this->wakeup_gesture.enabled; + this->wakeup_gesture.enabled = new; + device_init_wakeup(&this->pdev->dev, + this->wakeup_gesture.enabled ? 1 : 0); + touchctrl_notify_wakeup_gesture_mode(this, + this->wakeup_gesture.enabled); + if (!lazy_update && !this->dev_active && old != new) { + /* mode is changed in already suspended state */ + rc = clearpad_set_suspend_mode(this); + if (rc) + LOGE(this, "failed change suspend mode (rc=%d)\n", rc); + + } + LOGI(this, "wakeup gesture: %s", + this->wakeup_gesture.enabled ? "ENABLE" : "DISABLE"); + + UNLOCK(&this->lock); + + if (!lazy_update) + clearpad_ctrl_session_end(this, session); + +err_in_check_support: + return size; +} + +static ssize_t clearpad_force_sleep_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct clearpad_t *this = dev_get_drvdata(dev); + const char *session = "force sleep store"; + int rc = 0; + int value; + enum clearpad_force_sleep_e old; + bool lazy_update = false; + + LOGD(this, "start\n"); + + if (!this->post_probe.done) { + LOGI(this, "post_probe hasn't finished, will apply later\n"); + lazy_update = true; + goto err_in_check_post_probe; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + lazy_update = true; + goto not_ready_to_access_i2c; + } + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + LOGI(this, "not powered, will be applied later\n"); + lazy_update = true; + goto err_in_session_begin; + } + +err_in_session_begin: +not_ready_to_access_i2c: +err_in_check_post_probe: + LOCK(&this->lock); + this->wakeup.unblank_done = false; + this->wakeup.unblank_early_done = false; + old = this->force_sleep; + + rc = kstrtoint(buf, 0, &value); + if (rc) { + LOGE(this, "failed to read force_sleep\n"); + goto err_in_value; + } + this->force_sleep = value; + if (this->force_sleep < FSMODE_OFF || + FSMODE_ONESHOT < this->force_sleep) { + LOGE(this, "Invalid force_sleep mode\n"); + this->force_sleep = old; + goto err_in_value; + } + + if (old == FSMODE_ONESHOT && this->force_sleep == FSMODE_KEEP) { + LOGW(this, "refuse KEEP mode from ONESHOT mode\n"); + this->force_sleep = old; + } + LOG_STAT(this, "force_sleep: %d\n", this->force_sleep); + + if (!lazy_update) { + if (this->force_sleep == FSMODE_OFF && + this->state == SYN_STATE_RUNNING && + (!this->dev_active || this->early_suspend)) { + rc = clearpad_set_resume_mode(this); + if (rc) + LOGE(this, "failed to set resume for device\n"); + } else if (this->force_sleep != FSMODE_OFF && + this->state == SYN_STATE_RUNNING && + this->dev_active) { + rc = clearpad_set_early_suspend_mode(this); + if (rc) + LOGE(this, "failed to force sleep device\n"); + } + } +err_in_value: + UNLOCK(&this->lock); + + if (!lazy_update) + clearpad_ctrl_session_end(this, session); + + return size; +} + +static ssize_t clearpad_charger_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int rc = 0; + const char *session = "charger status store"; + struct clearpad_t *this = dev_get_drvdata(dev); + bool lazy_update = false; + + LOGD(this, "start\n"); + + if (!this->charger.supported) { + LOGI(this, "charger mode is not supported\n"); + goto err_in_check_support; + } + + if (!this->post_probe.done) { + LOGI(this, "post_probe hasn't finished, will apply later\n"); + lazy_update = true; + goto err_in_check_post_probe; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + lazy_update = true; + goto not_ready_to_access_i2c; + } + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + LOGI(this, "not powered, will be applied later\n"); + lazy_update = true; + goto err_in_session_begin; + } + +err_in_session_begin: +not_ready_to_access_i2c: +err_in_check_post_probe: + LOCK(&this->lock); + this->charger.status = sysfs_streq(buf, "0") ? false : true; + if (!lazy_update) { + rc = clearpad_set_charger(this); + if (rc) + LOGE(this, "failed to set charger for device\n"); + } + LOGI(this, "charger status: %s\n", + this->charger.status ? "CONN" : "DISCONN"); + UNLOCK(&this->lock); + + clearpad_ctrl_session_end(this, session); + +err_in_check_support: + return size; +} + +static ssize_t clearpad_cover_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int rc = 0; + const char *session = "cover status store"; + struct clearpad_t *this = dev_get_drvdata(dev); + bool lazy_update = false; + + if (!this->cover.supported) { + LOGI(this, "cover mode is not supported"); + goto err_in_check_support; + } + + if (!this->post_probe.done) { + LOGI(this, "post_probe hasn't finished, will apply later\n"); + lazy_update = true; + goto err_in_check_post_probe; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + lazy_update = true; + goto not_ready_to_access_i2c; + } + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + LOGI(this, "not powered, will be applied later\n"); + lazy_update = true; + goto err_in_session_begin; + } + +err_in_session_begin: +not_ready_to_access_i2c: +err_in_check_post_probe: + LOCK(&this->lock); + this->cover.status = sysfs_streq(buf, "0") ? false : true; + if (!lazy_update && this->cover.enabled) { + rc = clearpad_set_cover_status(this); + if (rc) + LOGE(this, "failed to set cover status for device\n"); + } + LOGI(this, "cover status: %s", this->cover.status ? "CLOSE" : "OPEN"); + UNLOCK(&this->lock); + + if (!lazy_update) + clearpad_ctrl_session_end(this, session); + +err_in_check_support: + return size; +} + +static ssize_t clearpad_cover_mode_enabled_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int rc = 0; + const char *session = "cover mode enabled store"; + struct clearpad_t *this = dev_get_drvdata(dev); + bool lazy_update = false; + + if (!this->cover.supported) { + LOGI(this, "cover mode is not supported"); + goto err_in_check_support; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + lazy_update = true; + goto not_ready_to_access_i2c; + } + + this->cover.enabled = sysfs_streq(buf, "0") ? false : true; + + if (!this->post_probe.done) { + LOGI(this, "post_probe hasn't finished, will apply later\n"); + lazy_update = true; + goto err_in_check_post_probe; + } + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + LOGI(this, "not powered, will be applied later\n"); + lazy_update = true; + goto err_in_session_begin; + } + +err_in_session_begin: +not_ready_to_access_i2c: +err_in_check_post_probe: + LOCK(&this->lock); + this->cover.enabled = sysfs_streq(buf, "0") ? false : true; + if (!lazy_update) { + if (this->cover.enabled) { + LOGI(this, "cover mode enabled\n"); + } else { + this->cover.status = false; + rc = clearpad_set_cover_status(this); + if (rc) + LOGE(this, "failed to set cover mode\n"); + LOGI(this, "cover mode disabled\n"); + } + } + UNLOCK(&this->lock); + + if (!lazy_update) + clearpad_ctrl_session_end(this, session); + +err_in_check_support: + return size; +} + +static ssize_t clearpad_cover_win_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int win_size = 0; + int win_size_org = 0; + int rc = 0; + const char *session = "cover win store"; + struct clearpad_t *this = dev_get_drvdata(dev); + bool lazy_update = false; + + if (!this->cover.supported) { + LOGI(this, "cover mode is not supported"); + goto err_in_check_support; + } + + if (!this->post_probe.done) { + LOGI(this, "post_probe hasn't finished, will apply later\n"); + lazy_update = true; + goto err_in_check_post_probe; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + lazy_update = true; + goto not_ready_to_access_i2c; + } + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + LOGI(this, "not powered, will be applied later\n"); + lazy_update = true; + goto err_in_session_begin; + } + +err_in_session_begin: +not_ready_to_access_i2c: +err_in_check_post_probe: + LOCK(&this->lock); + if (kstrtoint(buf, 0, &win_size)) { + LOGE(this, "failed to read %s", attr->attr.name); + rc = -EINVAL; + goto err_in_read_size; + } + win_size_org = win_size; + + if (!strncmp(attr->attr.name, "cover_win_top", PAGE_SIZE)) { + if (this->cover.convert_window_size && this->cover.tag_y_max) + win_size = win_size * (this->extents.preset_y_max + 1) / + this->cover.tag_y_max; + this->cover.win_top = win_size; + } else if (!strncmp(attr->attr.name, "cover_win_bottom", PAGE_SIZE)) { + if (this->cover.convert_window_size && this->cover.tag_y_max) + win_size = win_size * (this->extents.preset_y_max + 1) / + this->cover.tag_y_max; + this->cover.win_bottom = win_size; + } else if (!strncmp(attr->attr.name, "cover_win_right", PAGE_SIZE)) { + if (this->cover.convert_window_size && this->cover.tag_x_max) + win_size = win_size * (this->extents.preset_x_max + 1) / + this->cover.tag_x_max; + this->cover.win_right = win_size; + } else if (!strncmp(attr->attr.name, "cover_win_left", PAGE_SIZE)) { + if (this->cover.convert_window_size && this->cover.tag_x_max) + win_size = win_size * (this->extents.preset_x_max + 1) / + this->cover.tag_x_max; + this->cover.win_left = win_size; + } + if (!lazy_update) { + rc = clearpad_set_cover_window(this); + if (rc) + LOGE(this, "failed to set cover window for device\n"); + } +err_in_read_size: + LOGI(this, "%s = %d (org %d) rc = %d\n", + attr->attr.name, win_size, win_size_org, rc); + UNLOCK(&this->lock); + + if (!lazy_update) + clearpad_ctrl_session_end(this, session); + +err_in_check_support: + return size; +} + +static ssize_t clearpad_stamina_mode_enabled_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int rc = 0; + int value = 0; + const char *session = "stamina mode enabled store"; + struct clearpad_t *this = dev_get_drvdata(dev); + bool lazy_update = false; + + LOGD(this, "start\n"); + + if (!this->stamina.supported) { + LOGI(this, "stamina mode is not supported\n"); + goto err_in_check_support; + } + + if (!this->post_probe.done) { + LOGI(this, "post_probe hasn't finished, will apply later\n"); + lazy_update = true; + goto err_in_check_post_probe; + } + + if (!this->dev_active || this->interrupt.count == 0) { + LOGI(this, "avoid to access I2C before waiting %d ms delay\n", + this->reset.delay_for_powerup_ms); + lazy_update = true; + goto not_ready_to_access_i2c; + } + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + LOGI(this, "not powered, will be applied later\n"); + lazy_update = true; + goto err_in_session_begin; + } + +err_in_session_begin: +err_in_check_post_probe: +not_ready_to_access_i2c: + LOCK(&this->lock); + if (kstrtoint(buf, 0, &value)) { + LOGE(this, "failed to read %s", attr->attr.name); + rc = -EINVAL; + goto err_in_read_size; + } + switch (this->chip_id) { + case SYN_CHIP_3330: + case SYN_CHIP_332U: + if (value < 0 || 1 < value) { + LOGE(this, "invalid stamina report rate mode %d\n", + value); + goto err_in_read_size; + } + if (value) { + this->stamina.enabled = true; + this->stamina.change_reportrate.mode = 1; + } else { + this->stamina.enabled = false; + this->stamina.change_reportrate.mode = 0; + } + break; + case SYN_CHIP_3500: + if (value < 0 || 3 < value) { + LOGE(this, "invalid stamina report rate mode %d\n", + value); + goto err_in_read_size; + } + if (value) + this->stamina.enabled = true; + else + this->stamina.enabled = false; + this->stamina.change_reportrate.mode = value; + break; + default: + LOGE(this, "not supported on chip id 0x0%2x\n", this->chip_id); + goto err_in_read_size; + } + if (!lazy_update) { + rc = clearpad_set_stamina_mode(this); + if (rc) + LOGE(this, "failed to set stamina for device\n"); + } +err_in_read_size: + LOGI(this, "stamina mode %s\n", + this->stamina.enabled ? "enable" : "disable"); + LOGI(this, "change report rate mode %d\n", + this->stamina.change_reportrate.mode); + UNLOCK(&this->lock); + + if (!lazy_update) + clearpad_ctrl_session_end(this, session); + +err_in_check_support: + return size; +} + +static ssize_t clearpad_post_probe_start_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct clearpad_t *this = dev_get_drvdata(dev); + + LOGD(this, "start\n"); + + LOCK(&this->lock); + this->post_probe.start = sysfs_streq(buf, "0") ? false : true; + if (this->post_probe.done) { + HWLOGI(this, "already post probed, need reboot\n"); + } else { + if (this->post_probe.start) { + HWLOGI(this, "start post probe" + "with post_probe_start sysfs\n"); + schedule_delayed_work(&this->post_probe.work, 0); + } + } + UNLOCK(&this->lock); + + return size; +} + +static struct device_attribute clearpad_sysfs_attrs[] = { + __ATTR(fwinfo, S_IRUGO, clearpad_state_show, 0), + __ATTR(fwchip_id, S_IRUGO, clearpad_state_show, 0), + __ATTR(fwfamily, S_IRUGO, clearpad_state_show, 0), + __ATTR(fwrevision, S_IRUGO, clearpad_state_show, 0), + __ATTR(fwrevision_minor, S_IRUGO, clearpad_state_show, 0), + __ATTR(fwrevision_extra, S_IRUGO, clearpad_state_show, 0), + __ATTR(fwstate, S_IRUGO, clearpad_state_show, 0), + __ATTR(fwflash, S_IWUSR, 0, clearpad_fwflash_store), + __ATTR(enabled, S_IWUSR, 0, clearpad_enabled_store), + __ATTR(pen, S_IRUGO | S_IWUSR, clearpad_state_show, + clearpad_pen_enabled_store), + __ATTR(glove, S_IRUGO | S_IWUSR, clearpad_state_show, + clearpad_glove_enabled_store), + __ATTR(force_sleep, S_IRUGO | S_IWUSR, clearpad_state_show, + clearpad_force_sleep_store), + + __ATTR(charger_status, S_IRUGO | S_IWUSR, clearpad_state_show, + clearpad_charger_status_store), + __ATTR(cover_status, S_IRUGO | S_IWUSR, + clearpad_state_show, + clearpad_cover_status_store), + __ATTR(cover_mode_enabled, S_IRUGO | S_IWUSR, + clearpad_state_show, + clearpad_cover_mode_enabled_store), + __ATTR(cover_win_top, S_IRUGO | S_IWUSR, + clearpad_state_show, + clearpad_cover_win_store), + __ATTR(cover_win_bottom, S_IRUGO | S_IWUSR, + clearpad_state_show, + clearpad_cover_win_store), + __ATTR(cover_win_right, S_IRUGO | S_IWUSR, + clearpad_state_show, + clearpad_cover_win_store), + __ATTR(cover_win_left, S_IRUGO | S_IWUSR, + clearpad_state_show, + clearpad_cover_win_store), + __ATTR(stamina_mode, S_IRUGO | S_IWUSR, + clearpad_state_show, + clearpad_stamina_mode_enabled_store), + __ATTR(post_probe_start, S_IRUGO | S_IWUSR, + clearpad_state_show, + clearpad_post_probe_start_store), + __ATTR_NULL +}; + +static struct device_attribute clearpad_wakeup_gesture_attr = + __ATTR(wakeup_gesture, S_IRUGO | S_IWUSR, + clearpad_state_show, + clearpad_wakeup_gesture_store); + +static int clearpad_create_sysfs_entries(struct clearpad_t *this, + struct device_attribute *attrs) +{ + int i, rc = 0; + + for (i = 0; attrs[i].attr.name; i++) { + rc = device_create_file(&this->input->dev, &attrs[i]); + if (rc) + goto err_in_create_file; + } + goto end; + +err_in_create_file: + for (i = i - 1 ; i >= 0; --i) + device_remove_file(&this->input->dev, &attrs[i]); +end: + return rc; +} + +static void clearpad_remove_sysfs_entries(struct clearpad_t *this, + struct device_attribute *attrs) +{ + int i; + + for (i = 0; attrs[i].attr.name; i++) + device_remove_file(&this->input->dev, &attrs[i]); +} + +static int clearpad_read_config_u8(struct device_node *devnode, + char *conf_name, u8 *container) +{ + int rc = 0; + u32 value; + + if (!of_property_read_u32(devnode, conf_name, &value)) + *container = (u8)value; + else + rc = -EINVAL; + + return rc; +} + +static void clearpad_reg_offset_print(struct clearpad_t *this) +{ + /* F01_RMI */ + LOGD(this, "f01-cmd00:0x%02X\n", this->reg_offset.f01_cmd00); + LOGD(this, "f01-ctrl00:0x%02X\n", this->reg_offset.f01_ctrl00); + LOGD(this, "f01-ctrl01:0x%02X\n", this->reg_offset.f01_ctrl01); + LOGD(this, "f01-ctrl05:0x%02X\n", this->reg_offset.f01_ctrl05); + LOGD(this, "f01-ctrl18:0x%02X\n", this->reg_offset.f01_ctrl18); + LOGD(this, "f01-data00:0x%02X\n", this->reg_offset.f01_data00); + LOGD(this, "f01-data01:0x%02X\n", this->reg_offset.f01_data01); + LOGD(this, "f01-query11:0x%02X\n", this->reg_offset.f01_query11); + + /* F02_2D */ + LOGD(this, "f12-ctrl08:0x%02X\n", this->reg_offset.f12_ctrl08); + + /* F34_FLASH */ + LOGD(this, "f34-ctrl00:0x%02X\n", this->reg_offset.f34_ctrl00); + LOGD(this, "f34-data00:0x%02X\n", this->reg_offset.f34_data00); + LOGD(this, "f34-data01:0x%02X\n", this->reg_offset.f34_data01); + LOGD(this, "f34-data02:0x%02X\n", this->reg_offset.f34_data02); + LOGD(this, "f34-data03:0x%02X\n", this->reg_offset.f34_data03); + LOGD(this, "f34-data04:0x%02X\n", this->reg_offset.f34_data04); + LOGD(this, "f34-data05:0x%02X\n", this->reg_offset.f34_data05); + LOGD(this, "f34-query00:0x%02X\n", this->reg_offset.f34_query00); + LOGD(this, "f34-query01:0x%02X\n", this->reg_offset.f34_query01); + LOGD(this, "f34-query03:0x%02X\n", this->reg_offset.f34_query03); + + /* F51_CUSTOM */ + LOGD(this, "f51-ctrl05:0x%02X\n", this->reg_offset.f51_ctrl05); + LOGD(this, "f51-ctrl30:0x%02X\n", this->reg_offset.f51_ctrl30); + + /* F54_ANALOG */ + LOGD(this, "f54-cmd00:0x%02X\n", this->reg_offset.f54_cmd00); + LOGD(this, "f54-ctrl41:0x%02X\n", this->reg_offset.f54_ctrl41); + LOGD(this, "f54-ctrl57:0x%02X\n", this->reg_offset.f54_ctrl57); + LOGD(this, "f54-ctrl88:0x%02X\n", this->reg_offset.f54_ctrl88); + LOGD(this, "f54-ctrl109:0x%02X\n", this->reg_offset.f54_ctrl109); + LOGD(this, "f54-ctrl113:0x%02X\n", this->reg_offset.f54_ctrl113); + LOGD(this, "f54-ctrl147:0x%02X\n", this->reg_offset.f54_ctrl147); + LOGD(this, "f54-ctrl149:0x%02X\n", this->reg_offset.f54_ctrl149); + LOGD(this, "f54-ctrl188:0x%02X\n", this->reg_offset.f54_ctrl188); + LOGD(this, "f54-ctrl214:0x%02X\n", this->reg_offset.f54_ctrl214); + LOGD(this, "f54-data00:0x%02X\n", this->reg_offset.f54_data00); + LOGD(this, "f54-data01:0x%02X\n", this->reg_offset.f54_data01); + LOGD(this, "f54-data02:0x%02X\n", this->reg_offset.f54_data02); + LOGD(this, "f54-data03:0x%02X\n", this->reg_offset.f54_data03); + LOGD(this, "f54-data31:0x%02X\n", this->reg_offset.f54_data31); + LOGD(this, "f54-query38:0x%02X\n", this->reg_offset.f54_query38); +} + +static void clearpad_reg_offset_dt(struct clearpad_t *this, + struct device_node *devnode) +{ + if (!devnode) { + LOGW(this, "device node is invalid\n"); + return; + } + + /* F01_RMI */ + clearpad_read_config_u8(devnode, + "somc,clearpad-f01-rmi-cmd00", &this->reg_offset.f01_cmd00); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f01-rmi-ctrl00", &this->reg_offset.f01_ctrl00); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f01-rmi-ctrl01", &this->reg_offset.f01_ctrl01); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f01-rmi-ctrl05", &this->reg_offset.f01_ctrl05); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f01-rmi-ctrl18", &this->reg_offset.f01_ctrl18); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f01-rmi-data00", &this->reg_offset.f01_data00); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f01-rmi-data01", &this->reg_offset.f01_data01); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f01-rmi-query11", &this->reg_offset.f01_query11); + + /* F02_2D */ + clearpad_read_config_u8(devnode, + "somc,clearpad-f12-2d-ctrl08", &this->reg_offset.f12_ctrl08); + + /* F34_FLASH */ + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-ctrl00", &this->reg_offset.f34_ctrl00); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-data00", &this->reg_offset.f34_data00); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-data01", &this->reg_offset.f34_data01); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-data02", &this->reg_offset.f34_data02); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-data03", &this->reg_offset.f34_data03); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-data04", &this->reg_offset.f34_data04); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-data05", &this->reg_offset.f34_data05); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-query00", &this->reg_offset.f34_query00); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-query01", &this->reg_offset.f34_query01); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f34-flash-query03", &this->reg_offset.f34_query03); + + /* F51_CUSTOM */ + clearpad_read_config_u8(devnode, + "somc,clearpad-f51-custom-ctrl05", &this->reg_offset.f51_ctrl05); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f51-custom-ctrl30", &this->reg_offset.f51_ctrl30); + + /* F54_ANALOG */ + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-cmd00", &this->reg_offset.f54_cmd00); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-ctrl41", &this->reg_offset.f54_ctrl41); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-ctrl57", &this->reg_offset.f54_ctrl57); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-ctrl88", &this->reg_offset.f54_ctrl88); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-ctrl109", &this->reg_offset.f54_ctrl109); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-ctrl113", &this->reg_offset.f54_ctrl113); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-ctrl147", &this->reg_offset.f54_ctrl147); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-ctrl149", &this->reg_offset.f54_ctrl149); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-ctrl188", &this->reg_offset.f54_ctrl188); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-ctrl214", &this->reg_offset.f54_ctrl214); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-data00", &this->reg_offset.f54_data00); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-data01", &this->reg_offset.f54_data01); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-data02", &this->reg_offset.f54_data02); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-data03", &this->reg_offset.f54_data03); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-data31", &this->reg_offset.f54_data31); + + clearpad_read_config_u8(devnode, + "somc,clearpad-f54-analog-query38", &this->reg_offset.f54_query38); +} + +static void clearpad_reg_offset_config_dt(struct clearpad_t *this) +{ + struct device_node *devnode = this->bdata->of_node; + + clearpad_reg_offset_dt(this, devnode); +} + +static void clearpad_reg_offset_config_dt_for_extra_id( + struct clearpad_t *this, + struct device_node *chip_node) +{ + struct device_node *extra_node = NULL; + char extra_name[SYN_STRING_LENGTH]; + + snprintf(extra_name, SYN_STRING_LENGTH, + "EXTRA_0x%02X", this->device_info.firmware_revision_extra); + + extra_node = of_find_node_by_name(chip_node, extra_name); + if (extra_node == NULL) { + LOGE(this, "no settings for %s\n", extra_name); + return; + } + + LOGI(this, "read settings for %s\n", extra_name); + + clearpad_reg_offset_dt(this, extra_node); + clearpad_reg_offset_print(this); + + this->reg_offset.updated = true; +} + +static void clearpad_touch_config_dt_for_chip_id(struct clearpad_t *this, + int chip_id) +{ + struct device_node *dev_node = this->bdata->of_node; + struct device_node *chip_node = NULL; + const char *chip_name; + u32 value; + + if (chip_id) + chip_name = NAME_OF(clearpad_chip_name, chip_id); + else + chip_name = "clearpad_default"; + if (chip_name == NULL) { + LOGE(this, "unknown chip (0x%x)\n", chip_id); + return; + } + chip_node = of_find_node_by_name(dev_node, chip_name); + if (chip_node == NULL) { + LOGE(this, "no settings for %s\n", chip_name); + return; + } + + LOGI(this, "read settings for %s\n", chip_name); + + if (of_property_read_u32(chip_node, "flash_default_timeout_ms", &value)) + LOGW(this, "no flash_default_timeout_ms\n"); + else + this->flash.default_timeout_ms = (unsigned long)value; + + if (of_property_read_u32(chip_node, "calibrate_on_fwflash", &value)) + LOGW(this, "no calibrate_on_fwflash config\n"); + else + this->calibrate_on_fwflash = value ? true : false; + + if (of_property_read_u32(chip_node, "calibration_supported", &value)) + LOGW(this, "no calibration_supported\n"); + else + this->calibration_supported = value ? true : false; + + if (of_property_read_u32(chip_node, "hwreset_delay_for_powerup_ms", + &this->reset.delay_for_powerup_ms)) + LOGW(this, "no hwreset_delay_for_powerup_ms config\n"); + + if (of_property_read_u32(chip_node, "interrupt_default_wait_ms", + &this->interrupt.wait_ms)) + LOGW(this, "no interrupt_default_wait_ms config\n"); + + if (of_property_read_u32(chip_node, "charger_only_delay_ms", &value)) + LOGW(this, "no charger_only_delay_ms config\n"); + else + this->charger_only.delay_ms = (unsigned long)value; + + if (!this->reg_offset.updated) + clearpad_reg_offset_config_dt_for_extra_id(this, chip_node); +} + +static int clearpad_touch_config_dt(struct clearpad_t *this) +{ + int rc = 0; + struct device_node *devnode = this->bdata->of_node; + u32 value; + + if (of_property_read_u32(devnode, "chip_id", &this->chip_id)) + LOGW(this, "no chip_id config\n"); + + if (of_property_read_u32(devnode, "post_probe_start", &value)) + LOGW(this, "no post_probe_start config\n"); + else + this->post_probe.start = value ? true : false; + + if (of_property_read_string(devnode, "synaptics,firmware_name", + &this->flash.firmware_name)) + LOGW(this, "no firmware_name config\n"); + + if (of_property_read_u32(devnode, "flash_on_post_probe", &value)) + LOGW(this, "no flash_on_post_probe config\n"); + else + this->flash.on_post_probe = value ? true : false; + + if (of_property_read_u32(devnode, "flip_config", &this->flip_config)) + LOGW(this, "no flip_config config\n"); + + if (of_property_read_u32(devnode, "charger_supported", &value)) + LOGW(this, "no charger_supported config\n"); + else + this->charger.supported = value ? true : false; + + if (of_property_read_u32(devnode, "pen_supported", &value)) + LOGW(this, "no pen_supported config\n"); + else + this->pen.supported = value ? true : false; + + if (of_property_read_u32(devnode, "glove_supported", &value)) + LOGW(this, "no glove_supported config\n"); + else + this->glove.supported = value ? true : false; + + if (of_property_read_u32(devnode, "cover_supported", &value)) + LOGW(this, "no cover_supported config\n"); + else + this->cover.supported = value ? true : false; + + if (of_property_read_u32(devnode, "cover_tag_x_max", + &this->cover.tag_x_max)) + LOGW(this, "no cover_tag_x_max\n"); + + if (of_property_read_u32(devnode, "cover_tag_y_max", + &this->cover.tag_y_max)) + LOGW(this, "no cover_tag_y_max\n"); + + if (of_property_read_u32(devnode, "convert_cover_win_size", + &this->cover.convert_window_size)) + LOGW(this, "no convert_cover_win_size\n"); + + if (of_property_read_u32(devnode, "touch_pressure_enabled", + &this->touch_pressure_enabled)) + LOGW(this, "no touch_pressure_enabled\n"); + + if (of_property_read_u32(devnode, "touch_size_enabled", + &this->touch_size_enabled)) + LOGW(this, "no touch_size_enabled config\n"); + + if (of_property_read_u32(devnode, "touch_orientation_enabled", + &this->touch_orientation_enabled)) + LOGW(this, "no touch_orientation_enabled\n"); + + if (of_property_read_u32(devnode, "preset_x_max", + &this->extents.preset_x_max)) + LOGW(this, "no preset_x_max config\n"); + + if (of_property_read_u32(devnode, "preset_y_max", + &this->extents.preset_y_max)) + LOGW(this, "no preset_y_max config\n"); + + if (of_property_read_u32(devnode, "preset_n_fingers", + &this->extents.n_fingers)) + LOGW(this, "no preset_n_fingers config\n"); + + if (of_property_read_u32(devnode, "wakeup_gesture_supported", &value)) + LOGW(this, "no wakeup_gesture_supported\n"); + else + this->wakeup_gesture.supported = value ? true : false; + + if (of_property_read_u32(devnode, "wakeup_gesture_timeout", + &this->wakeup_gesture.timeout_delay)) + LOGW(this, "no wakeup_gesture_timeout\n"); + + if (of_property_read_u32(devnode, + "wakeup_gesture_use_workaround_for_felica", &value)) + LOGW(this, "no wakeup_gesture_use_workaround_for_felica\n"); + else + this->wakeup_gesture.use_workaround_for_felica = + value ? true : false; + + if (of_property_read_u32(devnode, "watchdog_enabled", &value)) + LOGW(this, "no watchdog_enabled\n"); + else + this->watchdog.enabled = value ? true : false; + + if (of_property_read_u32(devnode, "watchdog_delay_ms", &value)) { + LOGW(this, "no watchdog_delay_ms, watchdog is disabled\n"); + this->watchdog.enabled = false; + } else + this->watchdog.delay = msecs_to_jiffies(value); + + if (of_find_property(devnode, "synaptics,irq_gpio_noise_det", NULL)) { + this->noise_det.supported = true; + this->noise_det.irq_gpio = + of_get_named_gpio_flags(devnode, + "synaptics,irq_gpio_noise_det", 0, + &this->noise_det.irq_gpio_flags); + } else { + LOGI(this, "no synaptics,irq_gpio_noise_det config\n"); + this->noise_det.supported = false; + } + + if (of_property_read_u32(devnode, "noise_det_retrytime_ms", &value)) { + LOGI(this, "no noise_det_retrytime_ms and use default time\n"); + this->noise_det.retry_time_ms = + SYN_RETRY_DEFAULT_TIME_FOR_NOISE_DET; + } else { + this->noise_det.retry_time_ms = value; + } + + if (of_property_read_u32(devnode, "stamina_mode_supported", &value)) { + LOGW(this, "no stamina_mode_supported config\n"); + } else { + this->stamina.supported = + (value & SYN_STAMINA_MODE_SUPPORTED_MASK) ? true : false; + + this->stamina.change_reportrate.supported = + (value & SYN_STAMINA_REPROTRATE_SUPPORTED_MASK) ? true : false; + + this->stamina.doze_holdoff.supported = + (value & SYN_STAMINA_DOZE_HOLDOFF_SUPPORTED_MASK) + ? true : false; + } + + if (of_property_read_u32(devnode, "doze_default_time", &value)) + LOGW(this, "no doze_default_time config\n"); + else + this->stamina.doze_holdoff.default_time = (u8)value; + + if (of_property_read_u32(devnode, "doze_glove_mode_time", &value)) + LOGW(this, "no doze_glove_mode_time config\n"); + else + this->stamina.doze_holdoff.glove_mode_time = (u8)value; + + if (of_property_read_u32(devnode, "doze_cover_mode_time", &value)) + LOGW(this, "no doze_cover_mode_time config\n"); + else + this->stamina.doze_holdoff.cover_mode_time = (u8)value; + + /* read default register offset params */ + clearpad_reg_offset_config_dt(this); + + /* set default chip id settings */ + clearpad_touch_config_dt_for_chip_id(this, 0); + + return rc; +} + +static void clearpad_update_chip_id(struct clearpad_t *this) +{ + u8 *product_id = clearpad_s(this->device_info.product_id, + HEADER_PRODUCT_ID_SIZE); + int id; + + for (id = 0; id < ARRAY_SIZE(clearpad_chip_name); id++) { + if (clearpad_chip_name[id] == NULL) + continue; + if (is_equal_cstring(product_id, clearpad_chip_name[id])) { + this->chip_id = id; + goto update; + } + } +update: + LOGI(this, "chip_id=0x%x\n", this->chip_id); +} + +static void clearpad_set_is_sol(struct clearpad_t *this) +{ + this->is_sol = false; + if (this->chip_id == SYN_CHIP_3500) + this->is_sol = true; + LOGI(this, "is_sol=%s\n", this->is_sol ? "ture" : "false"); +} + +static int clearpad_input_init(struct clearpad_t *this) +{ + int rc = 0; + + if (this->input) { + LOGI(this, "already input device has been allocated\n"); + goto end; + } + + this->input = input_allocate_device(); + if (!this->input) { + rc = -ENOMEM; + goto end; + } + + input_set_drvdata(this->input, this); + + this->input->open = clearpad_device_open; + this->input->close = clearpad_device_close; + this->input->name = CLEARPAD_NAME; + this->input->id.vendor = SYN_CLEARPAD_VENDOR; + this->input->id.product = 1; + this->input->id.version = 1; + this->input->id.bustype = this->bdata->bustype; + + clearpad_funcarea_initialize(this); + + set_bit(EV_ABS, this->input->evbit); + + set_bit(ABS_MT_TRACKING_ID, this->input->absbit); + set_bit(ABS_MT_TOOL_TYPE, this->input->absbit); + + LOGI(this, "touch area [%d, %d, %d, %d]\n", + this->extents.x_min, this->extents.y_min, + this->extents.preset_x_max, this->extents.preset_y_max); + + rc = input_register_device(this->input); + if (rc) { + LOGE(this, "failed to register device\n"); + input_set_drvdata(this->input, NULL); + input_free_device(this->input); + this->input = NULL; + goto end; + } + +end: + return rc; +} + +static int clearpad_input_ev_init(struct clearpad_t *this) +{ + int rc = 0; + + if (this->evdt_node) { + LOGI(this, "already input ev has been initialized\n"); + goto end; + } + + if (this->wakeup_gesture.supported) { + this->evdt_node = evdt_initialize(this->bdata->dev, this->input, + SYN_WAKEUP_GESTURE); + if (!this->evdt_node) { + LOGE(this, "no wakeup_gesture dt\n"); + goto end; + } + + rc = device_create_file(&this->input->dev, + &clearpad_wakeup_gesture_attr); + if (rc) { + LOGE(this, "sysfs_create_file failed: %d\n", rc); + this->evdt_node = NULL; + goto end; + } + LOGI(this, "touch wakeup feature ok\n"); + device_init_wakeup(&this->pdev->dev, 0); + } +end: + return rc; +} + +static int clearpad_pm_suspend(struct device *dev) +{ + struct clearpad_t *this = dev_get_drvdata(dev); + + HWLOGI(this, "pm suspend was called\n"); + + if (device_may_wakeup(dev)) { + enable_irq_wake(this->irq); + HWLOGI(this, "enable irq wake"); + } + + HWLOGI(this, "pm suspend(active=%s)\n", + this->dev_active ? "true" : "false"); + + return 0; +} + +static int clearpad_pm_resume(struct device *dev) +{ + struct clearpad_t *this = dev_get_drvdata(dev); + + HWLOGI(this, "pm resume was called\n"); + if (device_may_wakeup(dev)) { + disable_irq_wake(this->irq); + HWLOGI(this, "disable irq wake"); + } + + HWLOGI(this, "pm resume(active=%s)\n", + this->dev_active ? "true" : "false"); + + return 0; +} + +/* + * fb and display + */ + +#ifdef CONFIG_FB + +/* need LOCK(&this->lock) */ +static void clearpad_powerdown_core(struct clearpad_t *this, const char *id) +{ + struct clearpad_touchctrl_t *touchctrl = &this->touchctrl; + struct timespec ts; + bool already_powerdown; + bool locked = false; + + get_monotonic_boottime(&ts); + already_powerdown = this->touchctrl.will_powerdown; + if (already_powerdown) { + HWLOGI(this, "received %s again " + "(power=%s icount=%u) @ %ld.%06ld\n", + id, touchctrl_is_touch_powered(this) ? "OK" : "NG", + this->interrupt.count, ts.tv_sec, ts.tv_nsec); + goto end; + } + HWLOGI(this, "%s (power=%s icount=%u) @ %ld.%06ld\n", + id, touchctrl_is_touch_powered(this) ? "OK" : "NG", + this->interrupt.count, ts.tv_sec, ts.tv_nsec); + + if (work_pending(&this->thread_resume.work)) + HWLOGI(this, "flushing pending thread_resume\n"); + UNLOCK(&this->lock); + flush_workqueue(this->thread_resume.work_queue); + LOCK(&this->lock); + locked = touchctrl_lock_power(this, __func__, true, false); + if (!locked) + /* TODO consider this fatal error case */ + LOGE(this, "failed to lock power(user=%d), " + "might cause suspend error\n", touchctrl->power_user); + + this->touchctrl.will_powerdown = true; + + /* suspend mode is set if no user */ + if (locked) + touchctrl_unlock_power(this, __func__); + +end: + return; +} + +static void clearpad_fb_early_powerdown_handler(struct clearpad_t *this) +{ + LOCK(&this->lock); + if (this->wakeup_gesture.enabled) + goto end; + + clearpad_powerdown_core(this, "EARLY POWERDOWN"); +end: + this->wakeup.unblank_early_done = false; + UNLOCK(&this->lock); + return; +} + +static void clearpad_fb_powerdown_handler(struct clearpad_t *this) +{ + LOCK(&this->lock); + if (this->wakeup_gesture.enabled) + clearpad_powerdown_core(this, "POWERDOWN"); + this->wakeup.unblank_done = false; + UNLOCK(&this->lock); + return; +} + +static void clearpad_fb_early_unblank_handler(struct clearpad_t *this) +{ + struct timespec ts; + unsigned long flags; + + if (this->wakeup.unblank_early_done) + return; + + get_monotonic_boottime(&ts); + LOCK(&this->lock); + this->wakeup.unblank_early_done = true; + + if (this->touchctrl.will_powerdown && this->touchctrl.power_user == 0) { + this->interrupt.count = 0; + spin_lock_irqsave(&this->slock, flags); + this->dev_busy = false; + this->irq_pending = false; + spin_unlock_irqrestore(&this->slock, flags); + } + + this->touchctrl.will_powerdown = false; + UNLOCK(&this->lock); + HWLOGI(this, "EARLY UNBLANK @ %ld.%06ld\n", ts.tv_sec, ts.tv_nsec); +} + +static void clearpad_fb_unblank_handler(struct clearpad_t *this) +{ + struct timespec ts; + bool power = touchctrl_is_touch_powered(this); + + get_monotonic_boottime(&ts); + HWLOGI(this, "UNBLANK (power=%s icount=%u active=%s) @ %ld.%06ld\n", + power ? "OK" : "NG", + this->interrupt.count, + this->dev_active ? "true" : "false", + ts.tv_sec, ts.tv_nsec); + + if (!power) { + HWLOGI(this, "ignore UNBLANK event before power on\n"); + return; + } + + if (this->wakeup.unblank_done) + return; + + LOCK(&this->lock); + this->wakeup.unblank_done = true; + if (!this->post_probe.done) { + HWLOGI(this, "ignore UNBLANK event before post probe\n"); + if (this->post_probe.start) { + HWLOGI(this, "schedule post probe work for fail-safe\n"); + schedule_delayed_work(&this->post_probe.work, 0); + } + goto err_in_post_probe_done; + } + + if (work_pending(&this->thread_resume.work)) + HWLOGI(this, "fb_unblank was called again before flushing\n"); + + HWLOGI(this, "schedule for thread resume operation\n"); + queue_work(this->thread_resume.work_queue, + &this->thread_resume.work); + +err_in_post_probe_done: + UNLOCK(&this->lock); + + get_monotonic_boottime(&ts); + HWLOGI(this, "end UNBLANK @ %ld.%06ld\n", + ts.tv_sec, ts.tv_nsec); +} + +static int clearpad_fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int blank; + struct clearpad_t *this = + container_of(self, struct clearpad_t, fb_notif); + + if (evdata && evdata->data) { + if (event == FB_EARLY_EVENT_BLANK || + event == FB_EXT_EARLY_EVENT_BLANK) { + blank = *(int *)evdata->data; + HWLOGI(this, "%s: %s\n", + (event == FB_EARLY_EVENT_BLANK) ? "Early" : + "ExtEarly", + (blank == FB_BLANK_POWERDOWN) ? "Powerdown" : + (blank == FB_BLANK_UNBLANK) ? "Unblank" : + "???"); + switch (blank) { + case FB_BLANK_POWERDOWN: + clearpad_fb_early_powerdown_handler(this); + break; + case FB_BLANK_UNBLANK: + clearpad_fb_early_unblank_handler(this); + break; + default: + break; + } + } else if (event == FB_EVENT_BLANK || + event == FB_EXT_EVENT_BLANK) { + blank = *(int *)evdata->data; + HWLOGI(this, "%s: %s\n", + (event == FB_EVENT_BLANK) ? "Blank" : + "ExtBlank", + (blank == FB_BLANK_POWERDOWN) ? "Powerdown" : + (blank == FB_BLANK_UNBLANK) ? "Unblank" : + "???"); + switch (blank) { + case FB_BLANK_POWERDOWN: + clearpad_fb_powerdown_handler(this); + break; + case FB_BLANK_UNBLANK: + clearpad_fb_unblank_handler(this); + default: + break; + } + } + } + return 0; +} + +#else +#error Need CONFIG_FB +#endif + + +/* + * analog test + */ + +#ifdef CONFIG_DEBUG_FS +static int clearpad_debug_hwtest_log(struct clearpad_t *this, + const char *format, ...) +{ + va_list args; + struct clearpad_hwtest_t *hwt = &this->hwtest; + int remain = sizeof(hwt->log_buf) - hwt->log_size; + int length = 0; + struct timespec ts; + + if (remain <= 1) { + /* Rewind */ + get_monotonic_boottime(&ts); + hwt->log_size = + scnprintf(hwt->log_buf, sizeof(hwt->log_buf), + "Rewound @ %ld.%06ld\n", + ts.tv_sec, ts.tv_nsec); + remain = sizeof(hwt->log_buf) - hwt->log_size; + BUG_ON(remain <= 1); + } + + va_start(args, format); + length = vscnprintf(hwt->log_buf + hwt->log_size, remain, + format, args); + va_end(args); + hwt->log_size += length; + + return length; +} + +static void clearpad_analog_test_get_loop_count(struct clearpad_t *this, + u8 mode, int num_tx, int num_rx, int *loop_count_i, + int *loop_count_j, int *data_type) +{ + switch (mode) { + case F54_16_IMAGE_REPORT: + case F54_AUTOSCAN_REPORT: + case F54_RAW_CAP_RX_COUPLING_REPORT: + case F54_SENSOR_SPEED_REPORT: + case F54_FULLINCELL_RAW_CAP_REPORT: + case F54_FULLINCELL_CAL_DATA_CHK_REPORT: + case F54_FULLINCELL_SENSOR_SPEED_REPORT: + case F54_TRX_TO_TRX_SHORT_RAW_IMAGE_REPORT: + *loop_count_i = num_tx; + *loop_count_j = num_rx; + *data_type = HWTEST_S16; + break; + case F54_HIGH_RESISTANCE_REPORT: + *loop_count_i = HWTEST_SIZE_OF_ONE_DIMENSION; + *loop_count_j = HWTEST_SIZE_OF_ONE_HIGH_RX; + *data_type = HWTEST_S16; + break; + case F54_TRX_TO_TRX_SHORT_2_REPORT: + if (this->chip_id == SYN_CHIP_3500) + *loop_count_i = HWTEST_SIZE_OF_TRX_SHORT_2; + else if (this->chip_id == SYN_CHIP_3330) + *loop_count_i = HWTEST_SIZE_OF_TRX_SHORT_2 + 1; + else + *loop_count_i = HWTEST_SIZE_OF_TRX_SHORT_2_TAB; + *loop_count_j = HWTEST_SIZE_OF_ONE_DIMENSION; + *data_type = HWTEST_U8; + break; + case F54_ABS_RAW_REPORT: + *loop_count_i = num_rx + num_tx; + *loop_count_j = HWTEST_SIZE_OF_ONE_DIMENSION; + *data_type = HWTEST_U32; + break; + case F54_EWMODE_RAW_CAP_REPORT: + *loop_count_i = num_rx; + *loop_count_j = HWTEST_SIZE_OF_ONE_DIMENSION; + *data_type = HWTEST_U32; + break; + default: + *loop_count_i = *loop_count_j = *data_type = 0; + break; + } + HWLOGI(this, "loop_count_i[%d], loop_count_j[%d], data_type[%d]\n", + *loop_count_i, *loop_count_j, *data_type); +} + +static void clearpad_analog_test(struct clearpad_t *this, + u8 f_analog, u8 mode, u8 count) +{ + int rc, i, j, k, len, num_tx = 0, num_rx = 0; + int loop_count_i, loop_count_j, data_type, data_size; + u8 buf[14], *data, *line, *pl, fw_rev_extra; + const char delimeter[] = " | "; + + /* Handle unsupported test report */ + switch (this->chip_id) { + case SYN_CHIP_3500: + switch (mode) { + case F54_16_IMAGE_REPORT: + case F54_AUTOSCAN_REPORT: + case F54_HIGH_RESISTANCE_REPORT: + case F54_RAW_CAP_RX_COUPLING_REPORT: + case F54_SENSOR_SPEED_REPORT: + case F54_TRX_TO_TRX_SHORT_2_REPORT: + break; + default: + HWLOGE(this, "analog test is not supported\n"); + goto end; + } + break; + case SYN_CHIP_3330: + switch (mode) { + case F54_16_IMAGE_REPORT: + case F54_AUTOSCAN_REPORT: + case F54_HIGH_RESISTANCE_REPORT: + case F54_RAW_CAP_RX_COUPLING_REPORT: + case F54_SENSOR_SPEED_REPORT: + case F54_TRX_TO_TRX_SHORT_2_REPORT: + case F54_EWMODE_RAW_CAP_REPORT: + case F54_ABS_RAW_REPORT: + case F54_TRX_TO_TRX_SHORT_RAW_IMAGE_REPORT: + break; + default: + HWLOGE(this, "analog test is not supported\n"); + goto end; + } + break; + case SYN_CHIP_332U: + switch (mode) { + case F54_16_IMAGE_REPORT: + case F54_FULLINCELL_RAW_CAP_REPORT: + case F54_FULLINCELL_CAL_DATA_CHK_REPORT: + case F54_FULLINCELL_SENSOR_SPEED_REPORT: + break; + default: + HWLOGE(this, "analog test is not supported\n"); + goto end; + } + break; + default: + HWLOGE(this, "unsupported chip id\n"); + goto end; + } + + memset(buf, 0, sizeof(buf)); + + LOCK(&this->lock); + + /* F01_RMI_CTRL00: Device Control */ + rc = clearpad_put_bit(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), + DEVICE_CONTROL_NO_SLEEP_MASK, + DEVICE_CONTROL_NO_SLEEP_MASK); + if (rc) + goto update_mode; + + /* Wait until sleep mode is completely changed to NO_SLEEP */ + clearpad_set_delay(100); + + /* F01_RMI_CTRL01: Interrupt Enable */ + rc = clearpad_put(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl01), + this->pdt[f_analog].irq_mask); + if (rc) + goto unset_no_sleep_mode; + + rc = clearpad_get_block(SYNF(this, F12_2D, CTRL, + this->reg_offset.f12_ctrl08), + buf, 14); + if (rc) + goto err_set_irq_xy; + num_rx = buf[12]; + num_tx = buf[13]; + + fw_rev_extra = this->device_info.firmware_revision_extra; + + if (this->chip_id == SYN_CHIP_332U) { + if (mode == F54_FULLINCELL_RAW_CAP_REPORT) { + /* F54_ANALOG_CTRL188: Start Calibration or Prod Test */ + rc = clearpad_put_bit( + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl188), + 0, START_CAL_PROD_TEST_SET_FREQUENCY_MASK); + if (rc) + goto err_set_irq_xy; + /* F54_ANALOG_CTRL188: Start Calibration or Prod Test */ + rc = clearpad_put_bit( + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl188), + START_CAL_PROD_TEST_START_PROD_TEST_MASK, + START_CAL_PROD_TEST_START_PROD_TEST_MASK); + if (rc) + goto err_set_irq_xy; + } + } else if (this->chip_id == SYN_CHIP_3500) { + if (mode == F54_RAW_CAP_RX_COUPLING_REPORT || + mode == F54_HIGH_RESISTANCE_REPORT || + mode == F54_TRX_TO_TRX_SHORT_2_REPORT) { + switch (fw_rev_extra) { + case 0x03: + /* F54_ANALOG_CTRL149: Trans CBC 2 */ + rc = clearpad_put_bit( + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl149), 0, + TRANS_CBC_2_TRANS_CBC_GLOBAL_CAP_MASK); + if (rc) + goto err_set_irq_xy; + /* F54_ANALOG_CTRL88: Analog Control 1 */ + rc = clearpad_put_bit( + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl88), 0, + ANALOG_CONTROL_1_CBC_XMTR_CARRIER_SELECT_MASK); + if (rc) + goto err_set_irq_xy; + /* F54_ANALOG_CTRL57: 0D CBC Settings */ + rc = clearpad_put_bit( + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl57), 0, + CBC_SETTINGS_XMTR_CARRIER_SELECT_MASK); + if (rc) + goto err_set_irq_xy; + /* F54_ANALOG_CTRL41: + Multimetric Noise Control*/ + rc = clearpad_put_bit( + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl41), + MULTIMETRIC_NOISE_CTRL_NO_SIGNAL_CLARITY_MASK, + MULTIMETRIC_NOISE_CTRL_NO_SIGNAL_CLARITY_MASK); + if (rc) + goto err_set_irq_xy; + + break; + default: + HWLOGE(this, "firmware is not supported\n"); + break; + } + /* F54_ANALOG_CMD00: Analog Command */ + rc = clearpad_put( + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + ANALOG_COMMAND_FORCE_UPDATE_MASK); + if (rc) + goto err_set_irq_xy; + rc = clearpad_get(SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + buf); + if (rc) + goto err_set_irq_xy; + for (i = 0; + BIT_GET(buf[0], ANALOG_COMMAND_FORCE_UPDATE) != 0; + i++) { + clearpad_set_delay( + SYN_WAIT_TIME_AFTER_REGISTER_ACCESS); + rc = clearpad_get( + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), buf); + if (rc || i > 100) + goto err_set_irq_xy; + HWLOGI(this, + "force update flag = %x, loop = %d\n", + buf[0], i); + } + /* F54_ANALOG_CMD00: Analog Command */ + rc = clearpad_put( + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + ANALOG_COMMAND_FORCE_CALIBRATION_MASK); + if (rc) + goto err_set_irq_xy; + rc = clearpad_get(SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + buf); + if (rc || BIT_GET(buf[0], ANALOG_COMMAND_GET_REPORT)) + goto err_set_irq_xy; + for (i = 0; + BIT_GET(buf[0], ANALOG_COMMAND_FORCE_CALIBRATION) != 0; + i++) { + clearpad_set_delay( + SYN_WAIT_TIME_AFTER_REGISTER_ACCESS); + rc = clearpad_get( + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), buf); + if (rc || i > 100) + goto err_set_irq_xy; + HWLOGI(this, "force cal flag = %x, loop = %d\n", + buf[0], i); + } + } + } + + clearpad_analog_test_get_loop_count(this, mode, num_tx, num_rx, + &loop_count_i, &loop_count_j, &data_type); + switch (data_type) { + case HWTEST_U8: + case HWTEST_S8: + data_size = sizeof(u8); + break; + case HWTEST_S16: + data_size = sizeof(s16); + break; + case HWTEST_U32: + data_size = sizeof(u32); + break; + default: + HWLOGE(this, "unsupported command\n"); + goto err_set_irq_xy; + } + + data = devm_kzalloc(&this->pdev->dev, loop_count_i * loop_count_j * data_size, + GFP_KERNEL); + if (!data) + goto err_set_irq_xy; + len = HWTEST_MAX_DIGITS + 1; + line = devm_kzalloc(&this->pdev->dev, + loop_count_j * (len + sizeof(delimeter)), + GFP_KERNEL); + if (!line) + goto err_kfree_data; + + for (k = 0; k < count; k++) { + s64 min_val = UINT_MAX, max_val = INT_MIN; + + HWLOGI(this, "ANALOG: mode[%d], num[%d], rx[%d], tx[%d]", + mode, k, num_rx, num_tx); + + rc = clearpad_put(SYNF(this, F54_ANALOG, DATA, + this->reg_offset.f54_data00), mode); + if (rc) + goto err_reset; + + clearpad_prepare_for_interrupt(this, &this->interrupt.for_F54, + "F54_ANALOG_CMD00 for analog test"); + + /* F54_ANALOG_CMD00: Analog Command */ + rc = clearpad_put( + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), + ANALOG_COMMAND_GET_REPORT_MASK); + if (rc) { + clearpad_undo_prepared_interrupt(this, + &this->interrupt.for_F54, + "F54_ANALOG_CMD00 for analog test"); + goto err_reset; + } + + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_F54, + this->interrupt.wait_ms); + LOCK(&this->lock); + if (rc) { + LOGE(this, "failed to get interrupt (rc=%d)\n", rc); + goto err_reset; + } + + rc = clearpad_put(SYNF(this, F54_ANALOG, DATA, + this->reg_offset.f54_data01), 0x00); + if (rc) + goto err_reset; + rc = clearpad_put(SYNF(this, F54_ANALOG, DATA, + this->reg_offset.f54_data02), 0x00); + if (rc) + goto err_reset; + clearpad_set_delay(20); + rc = clearpad_get_block( + SYNF(this, F54_ANALOG, DATA, this->reg_offset.f54_data03), + data, loop_count_i * loop_count_j * data_size); + if (rc) + goto err_reset; + for (i = 0; i < loop_count_i; i++) { + pl = line; + for (j = 0; j < loop_count_j; j++) { + s64 val = 0; + + switch (data_type) { + case HWTEST_U8: + val = (u8)(*(data + (i * loop_count_j) + j)); + break; + case HWTEST_S8: + val = (s8)(*(data + (i * loop_count_j) + j)); + break; + case HWTEST_S16: + val = (s16)le16_to_cpup( + (const u16 *)(data + ((i * loop_count_j) + j) * data_size)); + break; + case HWTEST_U32: + val = (u32)le32_to_cpup( + (const u32 *)(data + ((i * loop_count_j) + j) * data_size)); + break; + default: + break; + } + if (val >= max_val) + max_val = val; + if (val <= min_val) + min_val = val; + pl += snprintf(pl, len, "%6lld", val); + if ((j + 1) % loop_count_j) + pl += snprintf(pl, sizeof(delimeter), + delimeter); + } + HWLOGI(this, "%s\n", line); + } + HWLOGI(this, "MIN = %06lld / MAX = %06lld\n", min_val, max_val); + clearpad_set_delay(100); + } + +err_reset: + devm_kfree(&this->pdev->dev, line); + devm_kfree(&this->pdev->dev, data); + clearpad_reset(this, SYN_FORCE_SWRESET, __func__); + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_reset, + this->interrupt.wait_ms); + LOCK(&this->lock); + if (rc) + LOGE(this, "failed to get interrupt (rc=%d)\n", rc); + goto update_mode; + +err_kfree_data: + devm_kfree(&this->pdev->dev, data); +err_set_irq_xy: + if (clearpad_is_valid_function(this, SYN_F12_2D)) + clearpad_put(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl01), + this->pdt[SYN_F12_2D].irq_mask); +unset_no_sleep_mode: + /* F01_RMI_CTRL00: Device Control */ + clearpad_put_bit(SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), + 0, DEVICE_CONTROL_NO_SLEEP_MASK); +update_mode: + UNLOCK(&this->lock); +end: + return; +} + +static int clearpad_debug_hwtest_open(struct inode *inode, + struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int clearpad_hextou8(struct clearpad_t *this, + char **ptr, const char *guard, + u8 *value) +{ + int rc = 0; + char *p = *ptr; + char s[DEBUG_ONE_BYTE_HEX + 1]; + unsigned long v; + + p = skip_spaces(p); + if (p + DEBUG_ONE_BYTE_HEX > guard) { + rc = -EINVAL; + goto end; + } + strlcpy(s, p, DEBUG_ONE_BYTE_HEX + 1); + p += DEBUG_ONE_BYTE_HEX; + rc = kstrtoul(s, 16, &v); + if (rc) { + p = NULL; + goto end; + } + *value = (u8)v; + *ptr = skip_spaces(p); +end: + return rc; +} + +static int clearpad_debug_read_reg(struct clearpad_t *this, + u8 page, u8 reg) +{ + int rc; + u8 value; + + LOCK(&this->lock); + rc = clearpad_get(this, SYN_PAGE_ADDR(page, reg), &value); + if (!rc) + HWLOGI(this, "read page=0x%02x, addr=0x%02x, value=0x%02x\n", + page, reg, value); + else + HWLOGE(this, "error in reading single register\n"); + UNLOCK(&this->lock); + return rc; +} + +static int clearpad_debug_read_packet(struct clearpad_t *this, + u8 page, u8 reg, u8 length) +{ + int rc, i; + u8 *pkt; + + LOCK(&this->lock); + pkt = devm_kzalloc(&this->pdev->dev, length, GFP_KERNEL); + if (!pkt) { + rc = -ENOMEM; + goto end; + } + rc = clearpad_read_block(this, SYN_PAGE_ADDR(page, reg), pkt, length); + if (rc > 0) { + HWLOGI(this, "read page=0x%02x, addr=0x%02x\n", page, reg); + for (i = 0; i < length; i++) + HWLOGI(this, "index[%d]=0x%02x\n", i, pkt[i]); + rc = 0; + } else { + HWLOGE(this, "error in reading packet register\n"); + } + devm_kfree(&this->pdev->dev, pkt); +end: + UNLOCK(&this->lock); + return rc; +} + +static int clearpad_debug_write_reg(struct clearpad_t *this, + u8 page, u8 reg, u8 value) +{ + int rc; + + LOCK(&this->lock); + rc = clearpad_put(this, SYN_PAGE_ADDR(page, reg), value); + if (!rc) + HWLOGI(this, "write page=0x%02x, addr=0x%02x, value=0x%02x\n", + page, reg, value); + else + HWLOGE(this, "error in writing to register\n"); + UNLOCK(&this->lock); + return rc; +} + +static int clearpad_debug_write_packet(struct clearpad_t *this, + u8 page, u8 reg, u8 length, char *b, char *guard) +{ + u8 *pkt; + u8 index, value; + int rc, i; + + LOCK(&this->lock); + pkt = devm_kzalloc(&this->pdev->dev, length, GFP_KERNEL); + if (!pkt) { + rc = -ENOMEM; + goto end; + } + + /* read modified part of packet */ + rc = clearpad_read_block(this, SYN_PAGE_ADDR(page, reg), pkt, length); + if (rc < 0) + goto err_free; + + /* modify indexed data */ + while (b != NULL && *(b + 1) != '\0') { + if (clearpad_hextou8(this, &b, guard, &index) || + clearpad_hextou8(this, &b, guard, &value) || + index >= length) { + HWLOGE(this, "invalid arguments > %s\n", b); + rc = -EINVAL; + goto err_free; + } + HWLOGI(this, "mod index[%d]=0x%02x(0x%02x)\n", + index, value, pkt[index]); + pkt[index] = value; + } + + /* write back packet*/ + rc = clearpad_put_block(this, SYN_PAGE_ADDR(page, reg), pkt, length); + if (rc) { + HWLOGE(this, "error in writing to pkt register\n"); + goto err_free; + } + + HWLOGI(this, "write page=0x%02x, addr=0x%02x\n", page, reg); + for (i = 0; i < length; i++) + HWLOGI(this, "index[%d]=0x%02x\n", i, pkt[i]); + rc = 0; + +err_free: + devm_kfree(&this->pdev->dev, pkt); +end: + UNLOCK(&this->lock); + return rc; +} + +static int clearpad_debug_get_calibration_result(struct clearpad_t *this, + u8 check_mode) +{ + int rc = 0; + u8 buf; + + if (!this->calibration_supported) { + HWLOGE(this, "%s doesn't support calibration\n", + NAME_OF(clearpad_chip_name, this->chip_id)); + goto end; + } + + if (!clearpad_is_valid_function(this, SYN_F54_ANALOG)) { + rc = -EIO; + HWLOGE(this, "F54_ANALOG invalid\n"); + goto end; + } + LOCK(&this->lock); + rc = clearpad_get(SYNF(this, F54_ANALOG, DATA, + this->reg_offset.f54_data31), &buf); + UNLOCK(&this->lock); + if (rc) { + HWLOGE(this, "failed to get CRC\n"); + goto end; + } + + HWLOGI(this, "CRC = 0x%02x\n", buf); + + if (buf & check_mode) { + rc = -EIO; + HWLOGE(this, "calibration is not successful\n"); + } +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_debug_do_calibration(struct clearpad_t *this, int mode) +{ + int rc = 0; + + if (!this->calibration_supported) { + HWLOGE(this, "%s doesn't support calibration\n", + NAME_OF(clearpad_chip_name, this->chip_id)); + goto end; + } + + if (!clearpad_is_valid_function(this, SYN_F54_ANALOG)) { + rc = -EIO; + HWLOGE(this, "F54_ANALOG invalid\n"); + goto end; + } + + rc = clearpad_do_calibration(this, mode, + CALIBRATION_STATE_CALIBRATION_CRC_MASK | + CALIBRATION_STATE_IS_CALIBRATION_CRC_MASK); +end: + return rc; +} + +static int clearpad_debug_print_reg(const char *desc, struct clearpad_t *this, + u16 addr, u8 *buf, int length) +{ + int rc; + int i; + + rc = clearpad_get_block(this, addr, buf, length); + if (rc == 0) + for (i = 0; i < length; i++) + HWLOGI(this, "[0x%04x]/%02d 0x%02x %s\n", + addr, i, buf[i], i == 0 ? desc : ""); + else + HWLOGI(this, "[0x%04x] N/A %s\n", addr, desc); + + return rc; +} + +static void clearpad_debug_registers(struct clearpad_t *this) +{ + u8 buf[80]; + + LOCK(&this->lock); + if (!touchctrl_lock_power(this, __func__, true, false)) { + LOGI(this, "No register info due to no power\n"); + goto end; + } + + if (!clearpad_is_valid_function(this, SYN_F34_FLASH)) + goto reg_F01_RMI; + + HWLOGI(this, "=== F34_FLASH ===\n"); + + /* F34_FLASH_DATA00: Status */ + if (clearpad_debug_print_reg("F34_FLASH_DATA00: Status", + SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data00), buf, 1) == 0) { + HWLOGI(this, INDENT "Status = %d\n", + BIT_GET(buf[0], STATUS_FLASH_STATUS)); + HWLOGI(this, INDENT "Device Cfg Status = %d\n", + BIT_GET(buf[0], STATUS_DEVICE_CONFIG_STATUS)); + HWLOGI(this, INDENT "BL Mode = %d\n", + BIT_GET(buf[0], STATUS_BL_MODE)); + } + + /* F34_FLASH_QUERY01: Bootloader Revision */ + clearpad_debug_print_reg("F34_FLASH_QUERY01: Bootloader Revision", + SYNF(this, F34_FLASH, QUERY, + this->reg_offset.f34_query01), buf, 2); + + /* F34_FLASH_CTRL00: Customer Configuration ID */ + if (clearpad_debug_print_reg("F34_FLASH_CTRL00: Customer Config ID", + SYNF(this, F34_FLASH, CTRL, + this->reg_offset.f34_ctrl00), buf, 5) == 0) + HWLOGI(this, INDENT "family=0x%02x rev=0x%02x.%02x " + "extra=0x%02x aid=0x%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4]); + +reg_F01_RMI: + if (!clearpad_is_valid_function(this, SYN_F01_RMI)) + goto reg_F12_2D; + + HWLOGI(this, "=== F01_RMI ===\n"); + + /* F01_RMI_CTRL00: Device Control */ + if (clearpad_debug_print_reg("F01_RMI_CTRL00: Device Control", + SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl00), buf, 1) == 0) { + HWLOGI(this, INDENT "Sleep Mode = %d\n", + BIT_GET(buf[0], DEVICE_CONTROL_SLEEP_MODE)); + HWLOGI(this, INDENT "No Sleep = %d\n", + BIT_GET(buf[0], DEVICE_CONTROL_NO_SLEEP)); + HWLOGI(this, INDENT "Charger Connected = %d\n", + BIT_GET(buf[0], DEVICE_CONTROL_CHARGER_CONNECTED)); + HWLOGI(this, INDENT "Report Rate = %d\n", + BIT_GET(buf[0], DEVICE_CONTROL_REPORT_RATE)); + HWLOGI(this, INDENT "Configured = %d\n", + BIT_GET(buf[0], DEVICE_CONTROL_CONFIGURED)); + } + + /* F01_RMI_CTRL01: Interrupt Enable 0 */ + clearpad_debug_print_reg("F01_RMI_CTRL01: Interrupt Enable 0", + SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl01), buf, 1); + + /* F01_RMI_CTRL18: Device Control 1 */ + clearpad_debug_print_reg("F01_RMI_CTRL18: Device Control 1", + SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl18), buf, 1); + + /* F01_RMI_CTRL05: Doze Holdoff */ + clearpad_debug_print_reg("F01_RMI_CTRL05: Doze Holdoff", + SYNF(this, F01_RMI, CTRL, + this->reg_offset.f01_ctrl05), buf, 1); + + /* F01_RMI_DATA00: Device Status */ + if (clearpad_debug_print_reg("F01_RMI_DATA00: Device Status", + SYNF(this, F01_RMI, DATA, + this->reg_offset.f01_data00), buf, 1) == 0) { + HWLOGI(this, INDENT "Status Code = %d\n", + BIT_GET(buf[0], DEVICE_STATUS_CODE)); + HWLOGI(this, INDENT "Flash Prog = %d\n", + BIT_GET(buf[0], DEVICE_STATUS_FLASH_PROG)); + HWLOGI(this, INDENT "Unconfigured = %d\n", + BIT_GET(buf[0], DEVICE_STATUS_UNCONFIGURED)); + } + + /* F01_RMI_DATA01.00: Interrupt Status */ + clearpad_debug_print_reg("F01_RMI_DATA01.00: Interrupt Status", + SYNF(this, F01_RMI, DATA, + this->reg_offset.f01_data01), buf, 1); + +reg_F12_2D: + if (!clearpad_is_valid_function(this, SYN_F12_2D)) + goto reg_end; + + HWLOGI(this, "=== F12_2D ===\n"); + + /* F12_2D_DATA15: Object Attention */ + clearpad_debug_print_reg("F12_2D_DATA15: Object Attention", + SYNA(this, F12_2D, DATA, 15), buf, 2); + + /* F12_2D_DATA01: Object Type and Status 0-9 */ + if (clearpad_debug_print_reg("F12_2D_DATA01: Obj Type and Status 0-9", + SYNA(this, F12_2D, DATA, 01), buf, 8 * 10) == 0) { + int i; + u8 *b; + + for (i = 0; i < 10; i++) { + b = &buf[i * 8]; + HWLOGI(this, INDENT "Object %2d: (x,y)=(%d,%d) " + "w=(%d,%d) z=%d t=%d\n", + i, b[1] + (b[2] << 8), b[3] + (b[4] << 8), + b[6], b[7], b[5], b[0]); + } + } + + /* F12_2D_QUERY00: General */ + clearpad_debug_print_reg("F12_2D_QUERY00: General", + SYNA(this, F12_2D, QUERY, 0), buf, 1); + + /* F12_2D_QUERY10: Supported Object Types */ + if (this->chip_id == SYN_CHIP_3330) { + if (clearpad_debug_print_reg( + "F12_2D_QUERY10: Supported Object Types", + SYNA(this, F12_2D, QUERY, 10), buf, 1) == 0) { + HWLOGI(this, INDENT "Gloved Finger = %d\n", + BIT_GET(buf[0], + SUPPORTED_OBJECT_TYPES_HAS_GLOVED_FINGER)); + HWLOGI(this, INDENT "Narrow Object = %d\n", + BIT_GET(buf[0], + SUPPORTED_OBJECT_TYPES_HAS_NARROW_OBJECT)); + HWLOGI(this, INDENT "Hand Edge = %d\n", + BIT_GET(buf[0], + SUPPORTED_OBJECT_TYPES_HAS_HAND_EDGE)); + } + } else { + if (clearpad_debug_print_reg( + "F12_2D_QUERY10: Supported Object Types", + SYNA(this, F12_2D, QUERY, 10), buf, 2) == 0) { + HWLOGI(this, INDENT "Gloved Finger = %d\n", + BIT_GET(buf[0], + SUPPORTED_OBJECT_TYPES_HAS_GLOVED_FINGER)); + HWLOGI(this, INDENT "Cover = %d\n", + BIT_GET(buf[1], + SUPPORTED_OBJECT_TYPES_HAS_COVER)); + HWLOGI(this, INDENT "Stylus = %d\n", + BIT_GET(buf[1], + SUPPORTED_OBJECT_TYPES_HAS_STYLUS)); + HWLOGI(this, INDENT "Eraser = %d\n", + BIT_GET(buf[1], + SUPPORTED_OBJECT_TYPES_HAS_ERASER)); + HWLOGI(this, INDENT "Small Object = %d\n", + BIT_GET(buf[1], + SUPPORTED_OBJECT_TYPES_HAS_SMALL_OBJECT)); + } + } + + /* F12_2D_CTRL20_01: Report Flags */ + if (clearpad_debug_print_reg("F12_2D_CTRL20_01: Report Flags", + SYNA(this, F12_2D, CTRL, 20), buf, F12_2D_CTRL_RPT_REG_MAX) == 0) { + HWLOGI(this, INDENT "Report Always = %d\n", + BIT_GET(buf[F12_2D_CTRL_RPT_FLAG], + REPORT_FLAGS_REPORT_ALWAYS)); + HWLOGI(this, INDENT "Report Wakeup Gesture Only = %d\n", + BIT_GET(buf[F12_2D_CTRL_RPT_FLAG], + REPORT_FLAGS_REPORT_WAKEUP_GESTURE_ONLY)); + HWLOGI(this, INDENT "Enable Dribble = %d\n", + BIT_GET(buf[F12_2D_CTRL_RPT_FLAG], + REPORT_FLAGS_ENABLE_DRIBBLE)); + } + + /* F12_2D_CTRL23_00: Object Report Enable */ + if (clearpad_debug_print_reg("F12_2D_CTRL23_00: Object Report Enable", + SYNA(this, F12_2D, CTRL, 23), buf, 1) == 0) { + HWLOGI(this, INDENT "Finger = %d\n", + BIT_GET(buf[0], OBJECT_REPORT_ENABLE_FINGER)); + HWLOGI(this, INDENT "Stylus = %d\n", + BIT_GET(buf[0], OBJECT_REPORT_ENABLE_STYLUS)); + HWLOGI(this, INDENT "Palm = %d\n", + BIT_GET(buf[0], OBJECT_REPORT_ENABLE_PALM)); + HWLOGI(this, INDENT "Unclassified Object = %d\n", + BIT_GET(buf[0], OBJECT_REPORT_ENABLE_UNCLASSIFIED_OBJECT)); + HWLOGI(this, INDENT "Hovering Finger = %d\n", + BIT_GET(buf[0], OBJECT_REPORT_ENABLE_HOVERING_FINGER)); + HWLOGI(this, INDENT "Gloved Finger = %d\n", + BIT_GET(buf[0], OBJECT_REPORT_ENABLE_GLOVED_FINGER)); + HWLOGI(this, INDENT "Narrow Object = %d\n", + BIT_GET(buf[0], OBJECT_REPORT_ENABLE_NARROW_OBJECT)); + HWLOGI(this, INDENT "Hand Edge = %d\n", + BIT_GET(buf[0], OBJECT_REPORT_ENABLE_HAND_EDGE)); + } + + /* F12_2D_CTRL23_02: Report As Finger */ + if (clearpad_debug_print_reg("F12_2D_CTRL23_02: Report As Finger", + SYNA(this, F12_2D, CTRL, 23), buf, 3) == 0) { + HWLOGI(this, INDENT "Stylus = %d\n", + BIT_GET(buf[F12_2D_CTRL_REPORT_AS_FINGER], + REPORT_AS_FINGER_STYLUS)); + HWLOGI(this, INDENT "Palm = %d\n", + BIT_GET(buf[F12_2D_CTRL_REPORT_AS_FINGER], + REPORT_AS_FINGER_PALM)); + HWLOGI(this, INDENT "Unclassified Object = %d\n", + BIT_GET(buf[F12_2D_CTRL_REPORT_AS_FINGER], + REPORT_AS_FINGER_UNCLASSIFIED_OBJECT)); + HWLOGI(this, INDENT "Gloved Finger = %d\n", + BIT_GET(buf[F12_2D_CTRL_REPORT_AS_FINGER], + REPORT_AS_FINGER_GLOVED_FINGER)); + HWLOGI(this, INDENT "Narrow Object = %d\n", + BIT_GET(buf[F12_2D_CTRL_REPORT_AS_FINGER], + REPORT_AS_FINGER_NARROW_OBJECT)); + HWLOGI(this, INDENT "Hand Edge = %d\n", + BIT_GET(buf[F12_2D_CTRL_REPORT_AS_FINGER], + REPORT_AS_FINGER_HAND_EDGE)); + } + + if (this->chip_id == SYN_CHIP_3330 || + this->chip_id == SYN_CHIP_332U) { + /* F12_2D_CTRL25: Closed Xmin/Xmax/Ymin/Ymax */ + if (clearpad_debug_print_reg( + "F12_2D_CTRL25: Closed Xmin/Xmax/Ymin/Ymax", + SYNA(this, F12_2D, CTRL, 25), buf, 8) == 0) { + HWLOGI(this, INDENT "Closed Cover Xmin = %d\n", + ((buf[1] << 8) | buf[0])); + HWLOGI(this, INDENT " Xmax = %d\n", + ((buf[3] << 8) | buf[2])); + HWLOGI(this, INDENT " Ymin = %d\n", + ((buf[5] << 8) | buf[4])); + HWLOGI(this, INDENT " Ymax = %d\n", + ((buf[7] << 8) | buf[6])); + } + } + + /* F12_2D_CTRL26: Feature Enable */ + if (clearpad_debug_print_reg("F12_2D_CTRL26: Feature Enable", + SYNA(this, F12_2D, CTRL, 26), buf, 1) == 0) { + HWLOGI(this, INDENT "Glove Finger Detection = %d\n", + BIT_GET(buf[0], FEATURE_ENABLE_ENABLE_GLOVED_FINGER_DETECTION)); + HWLOGI(this, INDENT "Closed Cover Detection = %d\n", + BIT_GET(buf[0], FEATURE_ENABLE_ENABLE_CLOSED_COVER_DETECTION)); + } + + /* F12_2D_CTRL27_00: Wakeup Gesture Enable */ + if (clearpad_debug_print_reg("F12_2D_CTRL27_00: Wakeup Gesture Enable", + SYNA(this, F12_2D, CTRL, 27), buf, 1) == 0) { + HWLOGI(this, INDENT "Double Tap = %d\n", + BIT_GET(buf[0], WAKEUP_GESTURE_ENABLE_DOUBLE_TAP)); + HWLOGI(this, INDENT "Swipe = %d\n", + BIT_GET(buf[0], WAKEUP_GESTURE_ENABLE_SWIPE)); + HWLOGI(this, INDENT "Tap And Hold = %d\n", + BIT_GET(buf[0], WAKEUP_GESTURE_ENABLE_TAP_AND_HOLD)); + HWLOGI(this, INDENT "Circle = %d\n", + BIT_GET(buf[0], WAKEUP_GESTURE_ENABLE_CIRCLE)); + HWLOGI(this, INDENT "Triangle = %d\n", + BIT_GET(buf[0], WAKEUP_GESTURE_ENABLE_TRIANGLE)); + HWLOGI(this, INDENT "Vee = %d\n", + BIT_GET(buf[0], WAKEUP_GESTURE_ENABLE_VEE)); + HWLOGI(this, INDENT "Unicode = %d\n", + BIT_GET(buf[0], WAKEUP_GESTURE_ENABLE_UNICODE)); + } + + /* F12_2D_CTRL33_00: Multi-Finger Moisture General */ + if (clearpad_debug_print_reg("F12_2D_CTRL33_00: Multi-Finger " + "Moisture General", + SYNA(this, F12_2D, CTRL, 33), buf, 1) == 0) { + HWLOGI(this, INDENT "Enable Multifinger Moisture = %d\n", + BIT_GET(buf[0], ENABLE_MULTIFINGER_MOISTURE)); + } + if (!clearpad_is_valid_function(this, SYN_F54_ANALOG)) + goto reg_end; + + HWLOGI(this, "=== F51_CUSTOM ===\n"); + + if (this->chip_id == SYN_CHIP_3500) { + /* F51_CUSTOM_CTRL30_06: Custom Report Rate */ + if (clearpad_debug_print_reg( + "F51_CUSTOM_CTRL30_06: Custom Report Rate State", + SYNF(this, F51_CUSTOM, CTRL, + this->reg_offset.f51_ctrl30 + + SYN_EXTERNAL_REPORT_RATE_OFFSET), buf, 1) == 0) { + HWLOGI(this, + INDENT "Custom Report Rate Mode = %d\n", + *buf); + } + } + + HWLOGI(this, "=== F54_ANALOG ===\n"); + + if (this->calibration_supported) { + /* F54_ANALOG_DATA31: Calibration State */ + if (clearpad_debug_print_reg("F54_ANALOG_DATA31: Calibration " + "State", + SYNF(this, F54_ANALOG, DATA, + this->reg_offset.f54_data31), buf, 1) == 0) { + HWLOGI(this, INDENT "Normal Calibration CRC = %d\n", + BIT_GET(buf[0], + CALIBRATION_STATE_CALIBRATION_CRC)); + HWLOGI(this, INDENT "Wake-up Gesture Calibration " + "CRC = %d\n", + BIT_GET(buf[0], + CALIBRATION_STATE_IS_CALIBRATION_CRC)); + } + } + + /* F54_ANALOG_CMD00: Analog Command 0 */ + if (clearpad_debug_print_reg("F54_ANALOG_CMD00: Analog Command 0", + SYNF(this, F54_ANALOG, COMMAND, + this->reg_offset.f54_cmd00), buf, 1) == 0) { + HWLOGI(this, INDENT "Force Cal = %d\n", + BIT_GET(buf[0], ANALOG_COMMAND_FORCE_CALIBRATION)); + HWLOGI(this, INDENT "Force Update = %d\n", + BIT_GET(buf[0], ANALOG_COMMAND_FORCE_UPDATE)); + } + + if (this->chip_id == SYN_CHIP_3330) { + + /* F54_ANALOG_CTRL109_00: General Control */ + if (clearpad_debug_print_reg("F54_ANALOG_CTRL109_00: General Control", + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl109), + buf, 1) == 0) { + HWLOGI(this, INDENT "Baseline Correction Mode = %d\n", + BIT_GET(buf[0], BASELINE_CORRECTION_MODE)); + } + + /* F54_ANALOG_CTRL113_00: General Control */ + if (clearpad_debug_print_reg("F54_ANALOG_CTRL113_00: General Control", + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl113), + buf, 1) == 0) { + HWLOGI(this, INDENT "Disable Hybrid Baseline = %d\n", + BIT_GET(buf[0], DISABLE_HYBRID_BASELINE)); + } + + /* F54_ANALOG_CTRL147_00: Disable Hybrid CBC Auto Correction */ + if (clearpad_debug_print_reg("F54_ANALOG_CTRL147_00: General Control", + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl147), + buf, 1) == 0) { + HWLOGI(this, INDENT "Disable Hybrid CBC Auto Correction = %d\n", + BIT_GET(buf[0], DISABLE_HYBRID_CBC_AUTO_CORRECTION)); + } + + /* F54_ANALOG_CTRL214_00: General Control */ + if (clearpad_debug_print_reg("F54_ANALOG_CTRL214_00: General Control", + SYNF(this, F54_ANALOG, CTRL, + this->reg_offset.f54_ctrl214), + buf, 1) == 0) { + HWLOGI(this, INDENT "Enable Hybrid Charger noise " + "Mitigation = %d\n", + BIT_GET(buf[0], ENABLE_HYBRID_CHARGER_NOISE_MITIGATION)); + } + } + + clearpad_reg_offset_print(this); + +reg_end: + touchctrl_unlock_power(this, __func__); + +end: + UNLOCK(&this->lock); + return; +} + +static void clearpad_debug_info(struct clearpad_t *this) +{ + struct clearpad_touchctrl_t *touchctrl = &this->touchctrl; + + HWLOGI(this, "%s, family 0x%02x, fw rev 0x%02x.%02x, " + "extra 0x%02x, aid 0x%02x, state=%s, " + "active=%s, type=%s, irq=%s icount=%u\n", + clearpad_s(this->device_info.product_id, HEADER_PRODUCT_ID_SIZE), + this->device_info.customer_family, + this->device_info.firmware_revision_major, + this->device_info.firmware_revision_minor, + this->device_info.firmware_revision_extra, + this->device_info.analog_id, + NAME_OF(clearpad_state_name, this->state), + this->dev_active ? "true" : "false", + NAME_OF(clearpad_chip_name, this->chip_id), + this->irq_enabled ? "enabled" : "disabled", + this->interrupt.count); + + /* clearpad_post_probe_t */ + HWLOGI(this, "[post_probe] done=%s retry=%d\n", + this->post_probe.done ? "true" : "false", + this->post_probe.retry); + + /* clearpad_touchctrl_t */ + HWLOGI(this, "[power] touch=%s display=%s user=%d will_powerdown=%s\n", + touchctrl_is_touch_powered(this) ? "OK" : "NG", + touchctrl_is_display_powered(this) ? "OK" : "NG", + touchctrl->power_user, + touchctrl->will_powerdown ? "true" : "false"); + + /* clearpad_interrupt_t */ + HWLOGI(this, "[interrupt] hard_handler @ %ld.%06ld " + "threaded_handler @ %ld.%06ld handle_first_event @ %ld.%06ld\n", + this->interrupt.hard_handler_ts.tv_sec, + this->interrupt.hard_handler_ts.tv_nsec, + this->interrupt.threaded_handler_ts.tv_sec, + this->interrupt.threaded_handler_ts.tv_nsec, + this->interrupt.handle_first_event_ts.tv_sec, + this->interrupt.handle_first_event_ts.tv_nsec); + HWLOGI(this, INDENT "dev_busy=%s irq_pending=%s\n", + this->dev_busy ? "true" : "false", + this->irq_pending ? "true" : "false"); + HWLOGI(this, INDENT "reset(use=%s done=%s) " + "F34(use=%s done=%s) F54(use=%s done=%s)\n", + this->interrupt.for_reset.use ? "true" : "false", + atomic_read(&this->interrupt.for_reset.done) ? "true" : "false", + this->interrupt.for_F34.use ? "true" : "false", + atomic_read(&this->interrupt.for_F34.done) ? "true" : "false", + this->interrupt.for_F54.use ? "true" : "false", + atomic_read(&this->interrupt.for_F54.done) ? "true" : "false"); + + /* clearpad_noise_detect_t */ + HWLOGI(this, "[noise_detect] supported=%s 1st_irq=%s" + " retry_time_ms=%d\n", + this->noise_det.supported ? "true" : "false", + this->noise_det.first_irq ? "true" : "false", + this->noise_det.retry_time_ms); + HWLOGI(this, INDENT "enabled=%s hard_irq_c=%u threaded_irq_c=%u\n", + this->noise_det.enabled ? "true" : "false", + this->noise_det.hard_handler_count, + this->noise_det.threaded_handler_count); + HWLOGI(this, INDENT "hard_handler @ %ld.%06ld " + "threaded_handler @ %ld.%06ld\n", + this->noise_det.hard_handler_ts.tv_sec, + this->noise_det.hard_handler_ts.tv_nsec, + this->noise_det.threaded_handler_ts.tv_sec, + this->noise_det.threaded_handler_ts.tv_nsec); + + /* locks */ + HWLOGI(this, "[lock] this->lock: %s owner(%s:%d @ %ld.%06ld)\n", + IS_LOCKED(&this->lock) ? "LOCKED" : "UNLOCKED", + this->lock.owner_func, this->lock.owner_line, + this->lock.ts.tv_sec, this->lock.ts.tv_nsec); + HWLOGI(this, INDENT "session_lock: %s <%s> owner(%s:%d @ %ld.%06ld)\n", + IS_LOCKED(&touchctrl->session_lock) + ? "LOCKED" : "UNLOCKED", touchctrl->session, + touchctrl->session_lock.owner_func, + touchctrl->session_lock.owner_line, + touchctrl->session_lock.ts.tv_sec, + touchctrl->session_lock.ts.tv_nsec); + HWLOGI(this, INDENT "hwtest.lock: %s owner(%s:%d @ %ld.%06ld)\n", + IS_LOCKED(&this->hwtest.lock) ? "LOCKED" : "UNLOCKED", + this->hwtest.lock.owner_func, this->hwtest.lock.owner_line, + this->hwtest.lock.ts.tv_sec, this->hwtest.lock.ts.tv_nsec); + + /* feature flags */ + HWLOGI(this, "[force_sleep] mode=%d\n", this->force_sleep); + HWLOGI(this, "[charger] supported=%s status=%s\n", + this->charger.supported ? "true" : "false", + this->charger.status ? "true" : "false"); + HWLOGI(this, "[charger only] delay_ms=%lu\n", + this->charger_only.delay_ms); + HWLOGI(this, "[stylus] supported=%s enabled=%s\n", + this->pen.supported ? "true" : "false", + this->pen.enabled ? "true" : "false"); + HWLOGI(this, "[glove] supported=%s enabled=%s\n", + this->glove.supported ? "true" : "false", + this->glove.enabled ? "true" : "false"); + HWLOGI(this, "[cover] supported=%s status=%s enabled=%s\n", + this->cover.supported ? "true" : "false", + this->cover.status ? "true" : "false", + this->cover.enabled ? "true" : "false"); + HWLOGI(this, INDENT "win top=%d bottom=%d right=%d left=%d\n", + this->cover.win_top, this->cover.win_bottom, + this->cover.win_right, this->cover.win_left); + HWLOGI(this, INDENT "tag x_max=%u y_max=%u convert_window_size=%u\n", + this->cover.tag_x_max, this->cover.tag_y_max, + this->cover.convert_window_size); + HWLOGI(this, "[wakeup_gesture] supported=%s enabled=%s\n", + this->wakeup_gesture.supported ? "true" : "false", + this->wakeup_gesture.enabled ? "true" : "false"); + HWLOGI(this, "[watchdog] enabled=%s delay=%d\n", + this->watchdog.enabled ? "true" : "false", this->watchdog.delay); + HWLOGI(this, "[stamina_mode] supported=%s enabled=%s\n", + this->stamina.supported ? "true" : "false", + this->stamina.enabled ? "true" : "false"); + HWLOGI(this, INDENT "[change_reportrate] supported=%s mode=%d\n", + this->stamina.change_reportrate.supported ? "true" : "false", + this->stamina.change_reportrate.mode); + HWLOGI(this, INDENT "[doze holdoff] supported=%s default_time=%u " + "glove_mode_time=%u cover_mode_time=%u\n", + this->stamina.doze_holdoff.supported ? "true" : "false", + this->stamina.doze_holdoff.default_time, + this->stamina.doze_holdoff.glove_mode_time, + this->stamina.doze_holdoff.cover_mode_time); + HWLOGI(this, "[early unblank] done=%s early_done=%s\n", + this->wakeup.unblank_done ? "true" : "false", + this->wakeup.unblank_early_done ? "true" : "false"); +} + +static ssize_t clearpad_debug_hwtest_write(struct file *file, + const char __user *buf, size_t count, loff_t *pos) +{ + struct clearpad_t *this = (struct clearpad_t *)file->private_data; + struct clearpad_hwtest_t *hwt = &this->hwtest; + const char *session = "hwtest"; + int rc = 0; + unsigned long arg; + u8 page, reg, value, length, id; + int ms; + char *bhead = NULL; + char *b; + char *guard; + + /* print debug_info if no argument as default without lock */ + if (count < HWTEST_SIZE_OF_COMMAND_PREFIX || *pos != 0) { + clearpad_debug_info(this); + goto end; + } + + LOCK(&hwt->lock); + b = bhead = devm_kzalloc(&this->pdev->dev, count + 1, GFP_KERNEL); + if (!b) { + rc = -ENOMEM; + goto err_in_devm_kzalloc; + } + rc = strncpy_from_user(b, buf, count); + if (!rc) + goto err_in_strncpy_from_user; + + guard = b + count; + while (guard > b) { + if (isascii(guard[-1]) && isgraph(guard[-1])) + break; + guard[-1] = '\0'; + guard--; /* remove garbages */ + } + + + /* init hwtest log_buf with command */ + hwt->log_size = + scnprintf(hwt->log_buf, sizeof(hwt->log_buf), "%s\n", b); + + switch (DEBUG_COMMAND(b[0], b[1])) { + case DEBUG_COMMAND('R', 'B'): + case DEBUG_COMMAND('R', '0'): + /* RB/R0[2:page][2:reg] */ + b += HWTEST_SIZE_OF_COMMAND_PREFIX; + if (clearpad_hextou8(this, &b, guard, &page) || + clearpad_hextou8(this, &b, guard, ®)) + goto err_invalid_arg; + rc = clearpad_debug_read_reg(this, page, reg); + break; + case DEBUG_COMMAND('R', 'P'): + /* RP[2:page][2:reg] [2:length] */ + b += HWTEST_SIZE_OF_COMMAND_PREFIX; + if (clearpad_hextou8(this, &b, guard, &page) || + clearpad_hextou8(this, &b, guard, ®) || + clearpad_hextou8(this, &b, guard, &length)) + goto err_invalid_arg; + rc = clearpad_debug_read_packet(this, page, reg, length); + break; + case DEBUG_COMMAND('W', 'B'): + case DEBUG_COMMAND('W', '0'): + /* WB/W0[2:page][2:reg][2:value] */ + b += HWTEST_SIZE_OF_COMMAND_PREFIX; + if (clearpad_hextou8(this, &b, guard, &page) || + clearpad_hextou8(this, &b, guard, ®) || + clearpad_hextou8(this, &b, guard, &value)) + goto err_invalid_arg; + rc = clearpad_debug_write_reg(this, page, reg, value); + break; + case DEBUG_COMMAND('W', 'P'): + /* WP[2:page][2:reg] [2:length] [2:index][2:value] ... */ + b += HWTEST_SIZE_OF_COMMAND_PREFIX; + if (clearpad_hextou8(this, &b, guard, &page) || + clearpad_hextou8(this, &b, guard, ®) || + clearpad_hextou8(this, &b, guard, &length)) + goto err_invalid_arg; + rc = clearpad_debug_write_packet(this, page, reg, + length, b, guard); + break; + case DEBUG_COMMAND('A', '0'): + /* A0[2:test type][2:count] */ + b += HWTEST_SIZE_OF_COMMAND_PREFIX; + rc = kstrtoul(b, 16, &arg); + if (rc) + goto err_invalid_arg; + if (!clearpad_is_valid_function(this, SYN_F54_ANALOG)) { + HWLOGE(this, "F54 is not supported\n"); + goto err_invalid_arg; + } + value = arg; + reg = arg >> 8; + if (clearpad_ctrl_session_begin(this, session) == 0) { + clearpad_analog_test(this, SYN_F54_ANALOG, reg, value); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('R', 'H'): + /* RH/PO - HW reset */ + if (clearpad_ctrl_session_begin(this, session) == 0) { + LOCK(&this->lock); + clearpad_reset(this, SYN_HWRESET, "HW reset cmd"); + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_reset, + this->interrupt.wait_ms); + if (rc) + LOGE(this, "failed to get interrupt (rc=%d)\n", + rc); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('P', '0'): + case DEBUG_COMMAND('R', 'F'): + /* RH/PO - HW reset */ + if (clearpad_ctrl_session_begin(this, session) == 0) { + LOCK(&this->lock); + clearpad_reset(this, SYN_FORCE_HWRESET, "Force HW reset cmd"); + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_reset, + this->interrupt.wait_ms); + if (rc) + LOGE(this, "failed to get interrupt (rc=%d)\n", + rc); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('R', 'S'): + case DEBUG_COMMAND('P', '1'): + /* RS/P1 - SW reset */ + if (clearpad_ctrl_session_begin(this, session) == 0) { + LOCK(&this->lock); + clearpad_reset(this, SYN_SWRESET, "SW reset cmd"); + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_reset, + this->interrupt.wait_ms); + if (rc) + LOGE(this, "failed to get interrupt (rc=%d)\n", + rc); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('F', 'D'): + /* FD - FW default flash */ + b += HWTEST_SIZE_OF_COMMAND_PREFIX; + HWLOGI(this, "start default firmware flash\n"); + if (clearpad_ctrl_session_begin(this, session) == 0) { + LOCK(&this->lock); + rc = clearpad_fwflash_core(this, SYN_DEFAULT_FLASH, 0); + UNLOCK(&this->lock); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('F', 'F'): + /* FF[2:id] - FW force flash */ + b += HWTEST_SIZE_OF_COMMAND_PREFIX; + if (clearpad_hextou8(this, &b, guard, &id)) { + HWLOGE(this, "need module id for force flash\n"); + goto err_invalid_arg; + } + HWLOGI(this, "start force firmware flash\n"); + if (clearpad_ctrl_session_begin(this, session) == 0) { + LOCK(&this->lock); + rc = clearpad_fwflash_core(this, SYN_FORCE_FLASH, id); + UNLOCK(&this->lock); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('G', 'N'): + case DEBUG_COMMAND('C', '0'): + /* GN/C0 - get normal calibration result */ + if (clearpad_ctrl_session_begin(this, session) == 0) { + rc = clearpad_debug_get_calibration_result(this, + CALIBRATION_STATE_CALIBRATION_CRC_MASK); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('G', 'E'): + case DEBUG_COMMAND('C', '1'): + /* GE/C1 - get EW calibration result */ + if (clearpad_ctrl_session_begin(this, session) == 0) { + rc = clearpad_debug_get_calibration_result(this, + CALIBRATION_STATE_IS_CALIBRATION_CRC_MASK); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('C', 'N'): + case DEBUG_COMMAND('C', '2'): + /* CN/C2 - execute normal calibration */ + if (clearpad_ctrl_session_begin(this, session) == 0) { + LOCK(&this->lock); + rc = clearpad_debug_do_calibration(this, + SYN_CALIBRATION_NORMAL); + UNLOCK(&this->lock); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('C', 'E'): + case DEBUG_COMMAND('C', '3'): + /* CE/C3 - execute EW calibration */ + if (clearpad_ctrl_session_begin(this, session) == 0) { + LOCK(&this->lock); + rc = clearpad_debug_do_calibration(this, + SYN_CALIBRATION_EW); + UNLOCK(&this->lock); + clearpad_ctrl_session_end(this, session); + } + break; + case DEBUG_COMMAND('I', 'N'): + /* IN[cstring:subcommand] - incell command */ + b += HWTEST_SIZE_OF_COMMAND_PREFIX; + b = skip_spaces(b); + if (is_equal_cstring(b, "help")) { + HWLOGI(this, "usage: IN sub-command\n"); + HWLOGI(this, "sub-command: display_off, " + "lock_power, unlock_power\n"); + } else if (is_equal_cstring(b, "display_off")) { + rc = touchctrl_display_off(this); + } else if (is_equal_cstring(b, "lock_power")) { + LOCK(&this->lock); + rc = touchctrl_lock_power(this, __func__, true, false); + UNLOCK(&this->lock); + } else if (is_equal_cstring(b, "unlock_power")) { + LOCK(&this->lock); + touchctrl_unlock_power(this, __func__); + UNLOCK(&this->lock); + } + break; + case DEBUG_COMMAND('X', 'W'): + /* XW[number:interval(ms)] - watchdog (0:stop, else:start) */ + b += HWTEST_SIZE_OF_COMMAND_PREFIX; + b = skip_spaces(b); + cancel_delayed_work_sync(&this->watchdog.work); + if (kstrtoint(b, 0, &ms) || ms == 0) { + this->watchdog.enabled = false; + HWLOGI(this, "stop watchdog\n"); + } else { + this->watchdog.delay = msecs_to_jiffies(ms); + this->watchdog.enabled = true; + HWLOGI(this, "start watchdog (interval ms=%d)\n", ms); + schedule_delayed_work(&this->watchdog.work, + this->watchdog.delay); + } + break; + case DEBUG_COMMAND('X', 'R'): + /* XR - registers */ + clearpad_debug_registers(this); + break; + case DEBUG_COMMAND('X', 'X'): + /* XX - debug info */ + clearpad_debug_info(this); + break; + default: + goto err_invalid_arg; + } + goto end_free; + +err_invalid_arg: + HWLOGE(this, "illegal command\n"); + rc = -EINVAL; +err_in_strncpy_from_user: +end_free: + devm_kfree(&this->pdev->dev, bhead); +err_in_devm_kzalloc: + UNLOCK(&hwt->lock); +end: + return rc ? rc : count; +} + +static ssize_t clearpad_debug_hwtest_read(struct file *file, + char __user *buf, size_t count, loff_t *pos) +{ + struct clearpad_t *this = (struct clearpad_t *)file->private_data; + struct clearpad_hwtest_t *hwt = &this->hwtest; + ssize_t readable_size = min((ssize_t)hwt->log_size - (ssize_t)*pos, + (ssize_t)count); + ssize_t rc; + + LOCK(&hwt->lock); + if (readable_size <= 0) { + HWLOGE(this, "readable size <= 0\n"); + rc = 0; + goto end; + } + if (copy_to_user(buf, &hwt->log_buf[*pos], readable_size)) { + HWLOGE(this, "copying of buffer to read failed\n"); + rc = -EFAULT; + goto end; + } + *pos += readable_size; + rc = readable_size; +end: + UNLOCK(&hwt->lock); + return rc; +} + +/* for Bootloader v6.0 */ +/* need LOCK(&this->lock) */ +static int clearpad_read_pca_block_bl_v6_0(struct clearpad_t *this, + u16 block_num, u8 *data) +{ + int rc; + u16 block; + + block = block_num | + (FLASH_DATA_CONFIGURATION_AREA_SELECT_PERM << + FLASH_DATA_CONFIGURATION_AREA_SELECT_SHIFT); + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data00), + (u8 *)&block, 2); + if (rc) { + HWLOGE(this, "set block number error\n"); + goto end; + } + + /* issue read configuration block command */ + rc = clearpad_put(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data02), + FLASH_CONTROL_READ_CONFIGURATION_BLOCK); + if (rc) { + HWLOGE(this, "issue config error\n"); + goto end; + } + + /* read data block */ + rc = clearpad_get_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data01), + data, SYN_PCA_BLOCK_SIZE); + if (rc) { + HWLOGE(this, "read data error\n"); + goto end; + } + +end: + return rc; +} + +/* for Bootloader v7.x */ +/* need LOCK(&this->lock) */ +static int clearpad_read_pca_block_bl_v7_x(struct clearpad_t *this, + u16 block_num, u8 *data) +{ + int rc; + u16 payload_len = SYN_PAYLOAD_LENGTH; + + /* write partition id */ + rc = clearpad_put( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data01), + PID_GUEST_SERIALIZATION); + if (rc) { + HWLOGE(this, "set partition id error\n"); + goto end; + } + + /* set block number */ + rc = clearpad_put_block( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data02), + (u8 *)&block_num, 2); + if (rc) { + HWLOGE(this, "set block offset error\n"); + goto end; + } + + /* set payload length */ + rc = clearpad_put_block( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data03), + (u8 *)&payload_len, 2); + if (rc) { + HWLOGE(this, "set payload length error\n"); + goto end; + } + + clearpad_prepare_for_interrupt(this, &this->interrupt.for_F34, + "F34_FLASH_DATA04 for read pca"); + /* issue read command */ + /* F34_FLASH_DATA04: Programming Command */ + rc = clearpad_put( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data04), + FLASH_CMD_READ); + if (rc) { + HWLOGE(this, "set flash read command error\n"); + clearpad_undo_prepared_interrupt(this, + &this->interrupt.for_F34, + "F34_FLASH_DATA04 for read pca"); + goto end; + } + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, &this->interrupt.for_F34, + this->interrupt.wait_ms); + if (rc) { + HWLOGE(this, "wait for interrupt status failed %d\n", rc); + LOCK(&this->lock); + goto end; + } + LOCK(&this->lock); + + /* read pca block */ + rc = clearpad_get_block( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data05), + data, SYN_PCA_BLOCK_SIZE); + if (rc) { + HWLOGE(this, "read pca block error\n"); + goto end; + } + +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_read_pca_block(struct clearpad_t *this, + u16 block_num, u8 *data) +{ + int rc; + + if (this->is_sol) + rc = clearpad_read_pca_block_bl_v6_0(this, block_num, data); + else + rc = clearpad_read_pca_block_bl_v7_x(this, block_num, data); + if (rc) + HWLOGE(this, "failed pca read rc = %d\n", rc); + return rc; +} + +/* for Bootloader v6.0 */ +/* need LOCK(&this->lock) */ +static int clearpad_write_pca_block_bl_v6_0(struct clearpad_t *this, + u16 block_num, u8 *data) +{ + int rc; + u16 block; + u8 buf[2]; + + /* change to bootloader mode start */ + this->flash.enter_bootloader_mode = true; + + /* change to bootloader mode start */ + /* read bootloader id */ + rc = clearpad_get_block(SYNF(this, F34_FLASH, QUERY, + this->reg_offset.f34_query00), + buf, sizeof(buf)); + if (rc) { + HWLOGE(this, "get id error\n"); + goto end; + } + + /* write bootloader id to block data */ + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data01), + buf, sizeof(buf)); + if (rc) { + HWLOGE(this, "write id error\n"); + goto end; + } + + clearpad_prepare_for_interrupt(this, &this->interrupt.for_F34, + "F34_FLASH_DATA02 for write pca"); + + /* issue a flash program enable */ + rc = clearpad_put(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data02), + FLASH_CONTROL_ENABLE_FLASH_PROGRAMMING); + if (rc) { + HWLOGE(this, "issue config error\n"); + clearpad_undo_prepared_interrupt(this, + &this->interrupt.for_F34, + "F34_FLASH_DATA02 for write pca"); + goto end; + } + + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, &this->interrupt.for_F34, + this->interrupt.wait_ms); + if (rc) { + HWLOGE(this, "wait for interrupt status failed %d\n", rc); + LOCK(&this->lock); + goto err_exit_bl; + } + LOCK(&this->lock); + + /* reread PDT if it was changed. On success, driver can reset */ + rc = clearpad_read_pdt(this); + if (rc) { + HWLOGE(this, "set pdt error\n"); + goto err_exit_bl; + } + + /* make sure that we are in programming mode and there are no issues */ + rc = clearpad_get(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data03), + buf); + if (rc) { + HWLOGE(this, "get mode error\n"); + goto end; + } + + if (!(BIT_GET(buf[0], FLASH_STATUS_PROGRAM_ENABLED))) { + HWLOGE(this, "failed enabling flash (%s)\n", + clearpad_flash_status[buf[0] & 7]); + rc = -EIO; + goto end; + } + /* changing finished */ + + block = block_num | + (FLASH_DATA_CONFIGURATION_AREA_SELECT_PERM << + FLASH_DATA_CONFIGURATION_AREA_SELECT_SHIFT); + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data00), + (u8 *)&block, 2); + if (rc) { + HWLOGE(this, "set block offset error\n"); + goto err_exit_bl; + } + + /* write block data */ + rc = clearpad_put_block(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data01), + data, SYN_PCA_BLOCK_SIZE); + if (rc) { + dev_err(&this->pdev->dev, + "%s: set data error\n", __func__); + goto end; + } + + clearpad_prepare_for_interrupt(this, &this->interrupt.for_F34, + "F34_FLASH_DATA02 for write pca"); + + /* issue a write configuration block command */ + rc = clearpad_put(SYNF(this, F34_FLASH, DATA, + this->reg_offset.f34_data02), + FLASH_CONTROL_WRITE_CONFIGURATION_BLOCK); + if (rc) { + dev_err(&this->pdev->dev, + "%s: flash error\n", __func__); + clearpad_undo_prepared_interrupt(this, + &this->interrupt.for_F34, + "F34_FLASH_DATA02 for write pca"); + goto end; + } + + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, &this->interrupt.for_F34, + this->interrupt.wait_ms); + if (rc) + HWLOGE(this, "wait for interrupt status failed %d\n", rc); + LOCK(&this->lock); + +err_exit_bl: + /* exit bootloader mode */ + clearpad_reset(this, SYN_SWRESET, __func__); + + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, &this->interrupt.for_reset, + this->interrupt.wait_ms); + if (rc) + HWLOGE(this, "wait for interrupt status failed %d\n", rc); + LOCK(&this->lock); +end: + return rc; +} + +/* for Bootloader v7.x */ +/* need LOCK(&this->lock) */ +static int clearpad_write_pca_block_bl_v7_x(struct clearpad_t *this, + u16 block_num, u8 *data) +{ + int rc; + u8 buf, bl_buf[SYN_SINGLE_TRANSACTION_SIZE] = { + PID_BOOTLOADER, 0x00, 0x00, 0x00, 0x00, + FLASH_CMD_ENTER_BOOTLOADER}; + u16 payload_len = SYN_PAYLOAD_LENGTH; + + /* change to bootloader mode start */ + this->flash.enter_bootloader_mode = true; + + /* read flash program key */ + rc = clearpad_get_block( + SYNF(this, F34_FLASH, QUERY, this->reg_offset.f34_query01), + bl_buf + SYN_FP_KEY_OFFSET, 2); + if (rc) { + HWLOGE(this, "get boot loader revision error\n"); + goto end; + } + + clearpad_prepare_for_interrupt(this, &this->interrupt.for_F34, + "F34_FLASH_DATA01 for write pca"); + + /* issue command to enter bootloader mode with key*/ + /* F34_FLASH_DATA01: Partition ID + * F34_FLASH_DATA02_00: Block Offset + * F34_FLASH_DATA02_01: Block Offset + * F34_FLASH_DATA03_00: Data Transfer Settings + * F34_FLASH_DATA03_01: Data Transfer Settings + * F34_FLASH_DATA04: Programming Command + */ + rc = clearpad_put_block( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data01), + bl_buf, sizeof(bl_buf)); + if (rc) { + HWLOGE(this, "set bl mode error\n"); + clearpad_undo_prepared_interrupt(this, + &this->interrupt.for_F34, + "F34_FLASH_DATA01 for write pca"); + goto end; + } + + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, &this->interrupt.for_F34, + this->interrupt.wait_ms); + if (rc) { + HWLOGE(this, "wait for interrupt status failed %d\n", rc); + LOCK(&this->lock); + goto err_exit_bl; + } + LOCK(&this->lock); + + /* reread PDT if it was changed. On success, driver can reset */ + rc = clearpad_read_pdt(this); + if (rc) { + HWLOGE(this, "set pdt error\n"); + goto err_exit_bl; + } + + /* make sure that we are in programming mode and there are no issues */ + rc = clearpad_get( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data00), + &buf); + if (rc) { + HWLOGE(this, "failed to get flash programming status\n"); + goto err_exit_bl; + } + + if (!(BIT_GET(buf, STATUS_BL_MODE))) { + HWLOGE(this, "failed enabling flash (%s)\n", + NAME_OF(clearpad_flash_status_name, + BIT_GET(buf, STATUS_FLASH_STATUS))); + rc = -EIO; + goto err_exit_bl; + } + /* changing finished */ + + /* write partition id */ + rc = clearpad_put( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data01), + PID_GUEST_SERIALIZATION); + if (rc) { + HWLOGE(this, "set partition id error\n"); + goto err_exit_bl; + } + + /* set block number */ + rc = clearpad_put_block( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data02), + (u8 *)&block_num, 2); + if (rc) { + HWLOGE(this, "set block offset error\n"); + goto err_exit_bl; + } + + /* set payload length */ + rc = clearpad_put_block( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data03), + (u8 *)&payload_len, 2); + if (rc) { + HWLOGE(this, "set length error\n"); + goto err_exit_bl; + } + + /* write command */ + rc = clearpad_put( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data04), + FLASH_CMD_WRITE); + if (rc) { + HWLOGE(this, "set write command error\n"); + goto err_exit_bl; + } + + clearpad_prepare_for_interrupt(this, &this->interrupt.for_F34, + "F34_FLASH_DATA05 for write pca"); + + /* write pca block */ + /* F34_FLASH_DATA05: Payload */ + rc = clearpad_put_block( + SYNF(this, F34_FLASH, DATA, this->reg_offset.f34_data05), + data, SYN_PCA_BLOCK_SIZE); + if (rc) { + HWLOGE(this, "write error\n"); + clearpad_undo_prepared_interrupt(this, + &this->interrupt.for_F34, + "F34_FLASH_DATA05 for write pca"); + goto err_exit_bl; + } + + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, &this->interrupt.for_F34, + this->interrupt.wait_ms); + if (rc) + HWLOGE(this, "wait for interrupt status failed %d\n", rc); + LOCK(&this->lock); + +err_exit_bl: + /* exit bootloader mode */ + clearpad_reset(this, SYN_SWRESET, __func__); + + UNLOCK(&this->lock); + rc = clearpad_wait_for_interrupt(this, &this->interrupt.for_reset, + this->interrupt.wait_ms); + if (rc) + HWLOGE(this, "wait for interrupt status failed %d\n", rc); + LOCK(&this->lock); +end: + return rc; +} + +/* need LOCK(&this->lock) */ +static int clearpad_write_pca_block(struct clearpad_t *this, + u16 block_num, u8 *data) +{ + int rc; + + if (this->is_sol) + rc = clearpad_write_pca_block_bl_v6_0(this, block_num, data); + else + rc = clearpad_write_pca_block_bl_v7_x(this, block_num, data); + if (rc) + HWLOGE(this, "failed pca write rc = %d\n", rc); + return rc; +} + +static long clearpad_debug_pca_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct clearpad_t *this = (struct clearpad_t *)file->private_data; + struct clearpad_hwtest_t *hwt = &this->hwtest; + const char *session = "debug ioctl"; + struct clearpad_ioctl_pca_info pca_info; + int rc; + + LOCK(&hwt->lock); + rc = clearpad_ctrl_session_begin(this, session); + if (rc) + goto err_in_ctrl_begin; + + LOGI(this, "ioctl: %x\n", cmd); + if (copy_from_user(&pca_info, (void *) arg, + sizeof(struct clearpad_ioctl_pca_info))) { + rc = -EFAULT; + HWLOGE(this, "copy_from_user error\n"); + goto err_in_copy_from_user; + } + + switch (cmd) { + case SYN_PCA_IOCTL_GET: + LOCK(&this->lock); + rc = clearpad_read_pca_block(this, pca_info.block_pos, + pca_info.data); + UNLOCK(&this->lock); + if (rc) + break; + + if (copy_to_user((void *) arg, &pca_info, + sizeof(struct clearpad_ioctl_pca_info))) { + rc = -EFAULT; + HWLOGE(this, "copy_to_user error\n"); + } + break; + case SYN_PCA_IOCTL_SET: + LOCK(&this->lock); + rc = clearpad_write_pca_block(this, pca_info.block_pos, + pca_info.data); + UNLOCK(&this->lock); + break; + default: + rc = -EINVAL; + HWLOGE(this, "cmd %d error\n", cmd); + break; + } + +err_in_copy_from_user: + if (rc) + LOGE(this, "failed to access to touch device\n"); + + clearpad_ctrl_session_end(this, session); +err_in_ctrl_begin: + UNLOCK(&hwt->lock); + return rc; +} + +static const struct file_operations clearpad_debug_hwtest_fops = { + .owner = THIS_MODULE, + .open = clearpad_debug_hwtest_open, + .write = clearpad_debug_hwtest_write, + .read = clearpad_debug_hwtest_read, + .unlocked_ioctl = clearpad_debug_pca_ioctl, +}; + +static int clearpad_debug_init(struct clearpad_t *this) +{ + struct dentry *dent = NULL; + int rc = 0; + + mutex_init(&this->hwtest.lock.lock); + dent = debugfs_create_dir("clearpad", 0); + if (!dent || IS_ERR(dent)) { + HWLOGE(this, "debugfs_create_dir error: dent=0x%p\n", dent); + rc = -ENODEV; + goto end; + } + + this->debugfs = dent; + + dent = debugfs_create_file("hwtest", 0600, this->debugfs, + (void *)this, + &clearpad_debug_hwtest_fops); + if (!dent || IS_ERR(dent)) { + HWLOGE(this, "debugfs_create_file error: dent=0x%p\n", dent); + rc = -ENODEV; + goto error; + } + + goto end; + +error: + debugfs_remove_recursive(this->debugfs); + this->debugfs = NULL; +end: + return rc; +} +#endif /* CONFIG_DEBUG_FS */ + +static int clearpad_probe(struct platform_device *pdev) +{ + struct clearpad_data_t *cdata = pdev->dev.platform_data; + struct clearpad_t *this; + struct clearpad_touchctrl_t *touchctrl; + struct kobject *parent; + char *symlink_name; + struct timespec ts; + int rc; + bool retry = false; +#ifdef CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV + struct platform_device *rmi_dev; +#endif + this = devm_kzalloc(&pdev->dev, sizeof(struct clearpad_t), GFP_KERNEL); + if (!this) { + rc = -ENOMEM; + retry = true; + goto end; + } + /* Start logging for probe (no lock until end of probe) */ + get_monotonic_boottime(&ts); + this->hwtest.log_size = + scnprintf(this->hwtest.log_buf, sizeof(this->hwtest.log_buf), + "start probe @ %ld.%06ld\n", ts.tv_sec, ts.tv_nsec); + + this->state = SYN_STATE_INIT; + this->wakeup.unblank_done = false; + this->wakeup.unblank_early_done = false; + mutex_init(&this->lock.lock); + spin_lock_init(&this->slock); + + touchctrl = &this->touchctrl; + mutex_init(&touchctrl->session_lock.lock); + wake_lock_init(&touchctrl->wakelock, WAKE_LOCK_SUSPEND, WAKE_LOCK_ID); + + atomic_set(&this->interrupt.for_reset.done, 0); + init_waitqueue_head(&this->interrupt.for_reset.wq); + atomic_set(&this->interrupt.for_F34.done, 0); + init_waitqueue_head(&this->interrupt.for_F34.wq); + atomic_set(&this->interrupt.for_F54.done, 0); + init_waitqueue_head(&this->interrupt.for_F54.wq); + INIT_DELAYED_WORK(&this->reset.work, clearpad_reset_work); + INIT_DELAYED_WORK(&this->post_probe.work, clearpad_post_probe_work); + INIT_DELAYED_WORK(&this->watchdog.work, clearpad_watchdog_work); + + this->thread_resume.work_queue + = create_workqueue("clearpad_thread_resume"); + if (!this->thread_resume.work_queue) { + HWLOGE(this, "no create workqueue\n"); + rc = -EINVAL; + goto err_work_queue; + } + INIT_WORK(&this->thread_resume.work, clearpad_thread_resume_work); + + dev_set_drvdata(&pdev->dev, this); + /* LOGx is available after this */ + LOCK(&touchctrl->session_lock); + this->pdev = pdev; + this->pdata = cdata->pdata; + if (!this->pdata) { + HWLOGE(this, "no platform data\n"); + rc = -EINVAL; + goto err_free; + } + + this->bdata = cdata->bdata; + if (!this->bdata) { + HWLOGE(this, "no bus data\n"); + rc = -EINVAL; + goto err_free; + } + + if (this->bdata->of_node) { + rc = clearpad_touch_config_dt(this); + if (rc) { + HWLOGE(this, "err in device tree\n"); + goto err_free; + } + } + + spin_lock_init(&this->noise_det.slock); +#ifdef CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV + if (!cdata->rmi_dev) { + rmi_dev = platform_device_alloc(CLEARPAD_RMI_DEV_NAME, -1); + if (!rmi_dev) { + HWLOGE(this, "err in platform_device_alloc\n"); + rc = -ENOMEM; + retry = true; + goto err_free; + } + + rmi_dev->dev.parent = &pdev->dev; + rc = platform_device_add_data(rmi_dev, cdata, + sizeof(struct clearpad_data_t)); + if (rc) { + HWLOGE(this, "err in platform_device_add_data\n"); + goto err_device_put; + } + + rc = platform_device_add(rmi_dev); + if (rc) { + HWLOGE(this, "err in platform_device_add\n"); + goto err_device_put; + } + + if (!rmi_dev->dev.driver) { + HWLOGE(this, "no rmi dev\n"); + rc = -ENODEV; + goto err_device_del; + } + cdata->rmi_dev = rmi_dev; + } +#endif + +#ifdef CONFIG_DEBUG_FS + /* debugfs */ + rc = clearpad_debug_init(this); + if (rc) { + HWLOGE(this, "failed debug init\n"); + goto err_device_del; + } +#endif + +#ifdef CONFIG_FB + /* Execute post probe the first UNBLANK event + TODO : Must update after API update. */ + HWLOGI(this, "register fb callback\n"); + this->fb_notif.notifier_call = clearpad_fb_notifier_callback; + rc = fb_register_client(&this->fb_notif); + if (rc) { + HWLOGE(this, "unable to register fb_notifier\n"); + goto err_in_fb_register_client; + } +#endif + + this->force_sleep = FSMODE_OFF; + + this->irq = gpio_to_irq(this->pdata->irq_gpio); + rc = devm_request_threaded_irq(&this->pdev->dev, + this->irq, + clearpad_hard_handler, + clearpad_threaded_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + this->pdev->dev.driver->name, this); + if (rc) { + HWLOGE(this, "failed to request threaded irq %d (rc=%d)\n", + this->irq, rc); + goto err_in_request_threaded_irq; + } + disable_irq_nosync(this->irq); + + if (this->noise_det.supported) { + this->noise_det.irq = gpio_to_irq(this->noise_det.irq_gpio); + rc = devm_request_threaded_irq(&this->pdev->dev, + this->noise_det.irq, + clearpad_noise_det_hard_handler, + clearpad_noise_det_threaded_handler, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "clearpad_noise_det", this); + if (rc) { + HWLOGE(this, "failed to request threaded irq %d" + " (rc=%d)\n", + this->noise_det.irq, rc); + goto err_in_request_threaded_irq_gpio_noise_det; + } + disable_irq_nosync(this->noise_det.irq); + } + + HWLOGI(this, "input init\n"); + rc = clearpad_input_init(this); + if (rc) { + HWLOGE(this, "err in input init\n"); + goto err_in_input_init; + } + + HWLOGI(this, "ev init\n"); + rc = clearpad_input_ev_init(this); + if (rc) { + HWLOGE(this, "err in ev init\n"); + goto err_in_ev_init; + } + + /* sysfs */ + HWLOGI(this, "create sysfs\n"); + rc = clearpad_create_sysfs_entries(this, clearpad_sysfs_attrs); + if (rc) { + HWLOGE(this, "unable to create feature sysfs\n"); + goto err_in_create_sysfs_entries; + } + + /* create symlink */ + parent = this->input->dev.kobj.parent; + symlink_name = this->pdata->symlink_name ? : CLEARPAD_NAME; + rc = sysfs_create_link(parent, &this->input->dev.kobj, symlink_name); + if (rc) { + HWLOGE(this, "sysfs_create_link error\n"); + goto err_in_create_link; + } + + if (this->post_probe.start) { + HWLOGI(this, "schedule post probe\n"); + schedule_delayed_work(&this->post_probe.work, 0); + } else { + HWLOGI(this, "post_probe_start sysfs is required" + "to start post probe\n"); + } + UNLOCK(&touchctrl->session_lock); + goto end_log; + +err_in_create_link: + clearpad_remove_sysfs_entries(this, clearpad_sysfs_attrs); +err_in_create_sysfs_entries: +err_in_ev_init: +err_in_input_init: +err_in_request_threaded_irq_gpio_noise_det: +err_in_request_threaded_irq: +#ifdef CONFIG_FB + fb_unregister_client(&this->fb_notif); +err_in_fb_register_client: +#endif +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(this->debugfs); +#endif +err_device_del: +#ifdef CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV + platform_device_del(rmi_dev); +err_device_put: + platform_device_put(rmi_dev); +#endif +err_free: + UNLOCK(&touchctrl->session_lock); + dev_set_drvdata(&pdev->dev, NULL); + destroy_workqueue(this->thread_resume.work_queue); +err_work_queue: +end_log: + get_monotonic_boottime(&ts); + HWLOGI(this, "end probe @ %ld.%06ld (rc=%d)\n", + ts.tv_sec, ts.tv_nsec, rc); +end: + if (retry) { + if (cdata->probe_retry < SYN_RETRY_NUM_OF_PROBE) { + rc = -EPROBE_DEFER; + cdata->probe_retry++; + } + } + + return rc; +} + +static void clearpad_post_probe_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct clearpad_post_probe_t *post_probe + = container_of(dwork, struct clearpad_post_probe_t, work); + struct clearpad_t *this + = container_of(post_probe, struct clearpad_t, post_probe); + const char *session = "post probe"; + struct timespec ts; + + int retry; + bool do_reschedule = false; + int rc; + + LOCK(&this->lock); + if (this->post_probe.done) { + HWLOGI(this, "already post probe has been done\n"); + UNLOCK(&this->lock); + goto post_probe_done; + } + UNLOCK(&this->lock); + + get_monotonic_boottime(&ts); + HWLOGI(this, "start post probe @ %ld.%06ld\n", ts.tv_sec, ts.tv_nsec); + + rc = clearpad_ctrl_session_begin(this, session); + if (rc) { + HWLOGE(this, "failed to begin post probe session\n"); + do_reschedule = true; + goto err_in_ctrl_session_begin; + } + + WARN_ON(!touchctrl_is_display_powered(this)); + + LOCK(&this->lock); + if (!this->dev_active) { + rc = clearpad_set_resume_mode(this); + if (rc) + HWLOGE(this, "failed to set resume mode\n"); + } + if (this->flash.on_post_probe) { + this->state = SYN_STATE_DISABLED; + HWLOGI(this, "ensure firmware\n"); + for (retry = 0; retry < SYN_RETRY_NUM_OF_RECOVERY; retry++) { + rc = clearpad_fwflash_core(this, SYN_DEFAULT_FLASH, 0); + if (rc == 0) + break; + HWLOGI(this, "retry fwflash (%d)\n", retry); + clearpad_set_delay(50); + } + if (rc) { + rc = 0; + HWLOGW(this, "fw flash failed but continue init\n"); + } + } + if (this->chip_id == SYN_CHIP_3500) { + /* Remove this part after firmware flash sequence released */ + /* @ Yoshino1.0 */ + HWLOGW(this, "WA for Yoshino BU\n"); + clearpad_reset(this, SYN_SWRESET, __func__); + + this->state = SYN_STATE_RUNNING; + + UNLOCK(&this->lock); + + rc = clearpad_wait_for_interrupt(this, + &this->interrupt.for_reset, this->interrupt.wait_ms); + if (rc) + LOGE(this, "failed to get interrupt (rc=%d)\n", rc); + } else { + this->state = SYN_STATE_RUNNING; + + UNLOCK(&this->lock); + } + + clearpad_ctrl_session_end(this, session); + +err_in_ctrl_session_begin: + get_monotonic_boottime(&ts); + HWLOGI(this, "end post probe @ %ld.%06ld (rc=%d)\n", + ts.tv_sec, ts.tv_nsec, rc); + + if (do_reschedule) { + this->post_probe.retry++; + if (this->post_probe.retry <= SYN_RETRY_NUM_OF_POST_PROBE) { + HWLOGI(this, "reschedule post probe (%d)\n", + this->post_probe.retry); + schedule_delayed_work(&this->post_probe.work, 3 * HZ); + } else { + this->post_probe.retry = 0; + HWLOGE(this, "stop post probe\n"); + } + } + if (!rc) { + LOCK(&this->lock); + this->post_probe.done = true; + clearpad_set_feature_settings(this); + if (this->force_sleep != FSMODE_OFF && this->dev_active) { + rc = clearpad_set_suspend_mode(this); + if (rc) + HWLOGE(this, "failed to force sleep device\n"); + } + UNLOCK(&this->lock); + } + +post_probe_done: + return; +} + +static void clearpad_thread_resume_work(struct work_struct *work) +{ + struct clearpad_thread_resume_t *thread_resume + = container_of(work, struct clearpad_thread_resume_t, work); + struct clearpad_t *this + = container_of(thread_resume, + struct clearpad_t, thread_resume); + struct timespec ts; + bool locked = false; + + get_monotonic_boottime(&ts); + LOCK(&this->lock); + if (this->dev_active) { + HWLOGI(this, "device is already active\n"); + goto already_active; + } + + if (this->touchctrl.will_powerdown) { + HWLOGI(this, "not necessary to do thread_resume " + "(power=%s icount=%u) @ %ld.%06ld\n", + touchctrl_is_touch_powered(this) ? "OK" : "NG", + this->interrupt.count, ts.tv_sec, ts.tv_nsec); + goto will_powerdown; + } + + HWLOGI(this, "start thread_resume @ %ld.%06ld\n", + ts.tv_sec, ts.tv_nsec); + + locked = touchctrl_lock_power(this, "fb_unblank", true, false); + if (!locked) { + HWLOGW(this, "power is already turned off"); + goto end; + } + + this->interrupt.count = 0; + if (clearpad_handle_if_first_event(this) < 0) + LOGE(this, "failed to handle first event\n"); + + touchctrl_unlock_power(this, "fb_unblank"); + + get_monotonic_boottime(&ts); + HWLOGI(this, "end thread_resume @ %ld.%06ld\n", + ts.tv_sec, ts.tv_nsec); + goto end; + +already_active: +will_powerdown: +end: + UNLOCK(&this->lock); + return; +} + +static int clearpad_remove(struct platform_device *pdev) +{ +#ifdef CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV + struct clearpad_data_t *cdata = pdev->dev.platform_data; +#endif + struct clearpad_t *this = dev_get_drvdata(&pdev->dev); + struct clearpad_touchctrl_t *touchctrl = &this->touchctrl; + char *symlink_name = this->pdata->symlink_name ? : CLEARPAD_NAME; + + wake_lock_destroy(&touchctrl->wakelock); + + cancel_delayed_work_sync(&this->watchdog.work); + cancel_delayed_work_sync(&this->reset.work); + flush_workqueue(this->thread_resume.work_queue); + destroy_workqueue(this->thread_resume.work_queue); + device_init_wakeup(&this->pdev->dev, 0); + devm_free_irq(&this->pdev->dev, this->irq, this); + if (this->noise_det.supported) + devm_free_irq(&this->pdev->dev, this->noise_det.irq, this); + sysfs_remove_link(this->input->dev.kobj.parent, symlink_name); +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(this->debugfs); +#endif + clearpad_remove_sysfs_entries(this, clearpad_sysfs_attrs); +#ifdef CONFIG_FB + fb_unregister_client(&this->fb_notif); +#endif + input_unregister_device(this->input); +#ifdef CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV + platform_device_unregister(cdata->rmi_dev); +#endif + dev_set_drvdata(&pdev->dev, NULL); + return 0; +} + +static const struct dev_pm_ops clearpad_pm = { + .suspend = clearpad_pm_suspend, + .resume = clearpad_pm_resume, +}; + +static struct platform_driver clearpad_driver = { + .driver = { + .name = CLEARPAD_NAME, + .owner = THIS_MODULE, + .pm = &clearpad_pm, + }, + .probe = clearpad_probe, + .remove = clearpad_remove, +}; + +static int __init clearpad_init(void) +{ + return platform_driver_register(&clearpad_driver); +} + +static void __exit clearpad_exit(void) +{ + platform_driver_unregister(&clearpad_driver); +} + +late_initcall(clearpad_init); +module_exit(clearpad_exit); + +MODULE_DESCRIPTION(CLEARPAD_NAME "ClearPad Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/clearpad_i2c.c b/drivers/input/touchscreen/clearpad_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..45f98bf2dc5042b13dc1aba389a3f2aa0ad12db6 --- /dev/null +++ b/drivers/input/touchscreen/clearpad_i2c.c @@ -0,0 +1,343 @@ +/* linux/drivers/input/touchscreen/clearpad_i2c.c + * + * Copyright (c) 2011 Synaptics Incorporated + * Copyright (c) 2011 Unixphere + * + * Author: Yusuke Yoshimura + * + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLEARPAD_PAGE_SELECT_REGISTER 0xff +#define CLEARPAD_REG(addr) ((addr) & 0xff) +#define CLEARPAD_PAGE(addr) (((addr) >> 8) & 0xff) + +struct clearpad_i2c_t { + struct platform_device *pdev; + unsigned int page; + struct mutex page_mutex; +}; + +static int clearpad_i2c_set_page(struct device *dev, u8 page) +{ + struct clearpad_i2c_t *this = dev_get_drvdata(dev); + char txbuf[2] = {CLEARPAD_PAGE_SELECT_REGISTER, page}; + int rc = 0; + + rc = i2c_master_send(to_i2c_client(dev), txbuf, sizeof(txbuf)); + if (rc != sizeof(txbuf)) { + dev_err(dev, + "%s: set page failed: %d.", __func__, rc); + rc = (rc < 0) ? rc : -EIO; + goto exit; + } + this->page = page; + rc = 0; +exit: + return rc; +} + +static int clearpad_i2c_read(struct device *dev, u16 addr, u8 *buf, u8 len) +{ + struct clearpad_i2c_t *this = dev_get_drvdata(dev); + s32 rc = 0; + u8 page = CLEARPAD_PAGE(addr); + u8 reg = CLEARPAD_REG(addr); + int rsize = I2C_SMBUS_BLOCK_MAX; + int off; + + mutex_lock(&this->page_mutex); + + if (page != this->page) { + rc = clearpad_i2c_set_page(dev, page); + if (rc < 0) + goto exit; + } + + for (off = 0; off < len; off += rsize) { + if (len < off + I2C_SMBUS_BLOCK_MAX) + rsize = len - off; + rc = i2c_smbus_read_i2c_block_data(to_i2c_client(dev), + reg + off, rsize, &buf[off]); + if (rc != rsize) { + dev_err(dev, "%s: rc = %d\n", __func__, rc); + if (rc > 0) { + off += rc; + break; + } + goto exit; + } + } + rc = off; +exit: + mutex_unlock(&this->page_mutex); + return rc; +} + +static int clearpad_i2c_write(struct device *dev, u16 addr, + const u8 *buf, u8 len) +{ + struct clearpad_i2c_t *this = dev_get_drvdata(dev); + int rc = 0; + u8 reg = CLEARPAD_REG(addr); + u8 i; + + mutex_lock(&this->page_mutex); + + if (CLEARPAD_PAGE(addr) != this->page) { + rc = clearpad_i2c_set_page(dev, CLEARPAD_PAGE(addr)); + if (rc < 0) + goto exit; + } + + for (i = 0; i < len; i++) { + rc = i2c_smbus_write_byte_data(to_i2c_client(dev), + reg + i, buf[i]); + if (rc) + goto exit; + } + rc = i; +exit: + mutex_unlock(&this->page_mutex); + return rc; +} + +static int clearpad_i2c_read_block(struct device *dev, u16 addr, u8 *buf, + int len) +{ + struct clearpad_i2c_t *this = dev_get_drvdata(dev); + u8 txbuf[1] = {addr & 0xff}; + int rc = 0; + + mutex_lock(&this->page_mutex); + + if (CLEARPAD_PAGE(addr) != this->page) { + rc = clearpad_i2c_set_page(dev, CLEARPAD_PAGE(addr)); + if (rc < 0) + goto exit; + } + + rc = i2c_master_send(to_i2c_client(dev), txbuf, sizeof(txbuf)); + if (rc != sizeof(txbuf)) { + rc = (rc < 0) ? rc : -EIO; + goto exit; + } + + rc = i2c_master_recv(to_i2c_client(dev), buf, len); + if (rc < 0) + dev_err(dev, "%s: rc = %d\n", __func__, rc); +exit: + mutex_unlock(&this->page_mutex); + return rc; +} + +static int clearpad_i2c_write_block(struct device *dev, u16 addr, const u8 *buf, + int len) +{ + struct clearpad_i2c_t *this = dev_get_drvdata(dev); + u8 txbuf[len + 1]; + int rc = 0; + + txbuf[0] = addr & 0xff; + memcpy(txbuf + 1, buf, len); + + mutex_lock(&this->page_mutex); + + if (CLEARPAD_PAGE(addr) != this->page) { + rc = clearpad_i2c_set_page(dev, CLEARPAD_PAGE(addr)); + if (rc < 0) + goto exit; + } + + rc = i2c_master_send(to_i2c_client(dev), txbuf, sizeof(txbuf)); + if (rc < 0) + dev_err(dev, "%s: rc = %d\n", __func__, rc); + else + rc -= 1; +exit: + mutex_unlock(&this->page_mutex); + return rc; +} + +static struct clearpad_bus_data_t clearpad_i2c_bus_data = { + .bustype = BUS_I2C, + .set_page = clearpad_i2c_set_page, + .read = clearpad_i2c_read, + .write = clearpad_i2c_write, + .read_block = clearpad_i2c_read_block, + .write_block = clearpad_i2c_write_block, +}; + +#ifdef CONFIG_OF +static int clearpad_parse_dt(struct device *dev, + struct clearpad_platform_data_t *pdata) +{ + struct device_node *np = dev->of_node; + + pdata->irq_gpio = of_get_named_gpio_flags(np, "synaptics,irq_gpio", + 0, &pdata->irq_gpio_flags); + return 0; +} +#else +static int clearpad_parse_dt(struct device *dev, + struct clearpad_platform_data *pdata) +{ + return -ENODEV; +} +#endif + +static int clearpad_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct clearpad_data_t clearpad_data = { + .pdata = NULL, + .bdata = &clearpad_i2c_bus_data, + .probe_retry = 0, +#ifdef CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV + .rmi_dev = NULL, +#endif + }; + struct clearpad_i2c_t *this; + int rc; + + if (client->dev.of_node) { + clearpad_data.pdata = devm_kzalloc(&client->dev, + sizeof(struct clearpad_platform_data_t), + GFP_KERNEL); + if (!clearpad_data.pdata) { + dev_err(&client->dev, "failed to allocate memory\n"); + rc = -ENOMEM; + goto exit; + } + rc = clearpad_parse_dt(&client->dev, clearpad_data.pdata); + if (rc) { + dev_err(&client->dev, "failed to parse device tree\n"); + goto exit; + } + } else { + clearpad_data.pdata = client->dev.platform_data; + } + + this = kzalloc(sizeof(struct clearpad_i2c_t), GFP_KERNEL); + if (!this) { + rc = -ENOMEM; + goto exit; + } + + dev_set_drvdata(&client->dev, this); + + mutex_init(&this->page_mutex); + + this->pdev = platform_device_alloc(CLEARPAD_NAME, -1); + if (!this->pdev) { + rc = -ENOMEM; + goto err_free; + } + clearpad_data.bdata->dev = &client->dev; + clearpad_data.bdata->of_node = client->dev.of_node; + this->pdev->dev.parent = &client->dev; + rc = platform_device_add_data(this->pdev, + &clearpad_data, sizeof(clearpad_data)); + if (rc) + goto err_device_put; + + rc = platform_device_add(this->pdev); + if (rc) + goto err_device_put; + + dev_info(&client->dev, "%s: success\n", __func__); + goto exit; + +err_device_put: + platform_device_put(this->pdev); +err_free: + dev_set_drvdata(&client->dev, NULL); + kfree(this); +exit: + return rc; +} + +static int clearpad_i2c_remove(struct i2c_client *client) +{ + struct clearpad_i2c_t *this = dev_get_drvdata(&client->dev); + platform_device_unregister(this->pdev); + dev_set_drvdata(&client->dev, NULL); + kfree(this); + return 0; +} + +static const struct i2c_device_id clearpad_id[] = { + { CLEARPADI2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, clearpad_id); + +#ifdef CONFIG_OF +static struct of_device_id clearpad_match_table[] = { + { .compatible = "synaptics,clearpad", }, + { }, +}; +#else +#define clearpad_match_table NULL +#endif + +static struct i2c_driver clearpad_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = CLEARPADI2C_NAME, + .of_match_table = clearpad_match_table, + }, + .id_table = clearpad_id, + .probe = clearpad_i2c_probe, + .remove = clearpad_i2c_remove, +}; + +#ifndef MODULE +void clearpad_i2c_init_async(void *unused, async_cookie_t cookie) +{ + int rc; + + rc = i2c_add_driver(&clearpad_i2c_driver); + if (rc != 0) + pr_err("Clearpad I2C registration failed rc = %d\n", rc); +} +#endif + +static int __init clearpad_i2c_init(void) +{ +#ifdef MODULE + return i2c_add_driver(&clearpad_i2c_driver); +#else + async_schedule(clearpad_i2c_init_async, NULL); + return 0; +#endif +} + +static void __exit clearpad_i2c_exit(void) +{ + i2c_del_driver(&clearpad_i2c_driver); +} + +MODULE_DESCRIPTION(CLEARPADI2C_NAME "ClearPad I2C Driver"); +MODULE_LICENSE("GPL v2"); + +module_init(clearpad_i2c_init); +module_exit(clearpad_i2c_exit); diff --git a/drivers/input/touchscreen/clearpad_rmi_dev.c b/drivers/input/touchscreen/clearpad_rmi_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..226e3c4348a912bea8c8472aa4a4f738a8efa693 --- /dev/null +++ b/drivers/input/touchscreen/clearpad_rmi_dev.c @@ -0,0 +1,507 @@ +/* linux/drivers/input/touchscreen/clearpad_rmi_dev.c + * + * 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. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHAR_DEVICE_NAME "rmi" +#define DEVICE_CLASS_NAME "rmidev" + +#define RMI_CHAR_DEV_TMPBUF_SZ (1024 * 8) +#define RMI_REG_ADDR_PAGE_SELECT 0xFF +#define REG_ADDR_LIMIT 0xFFFF + +struct rmidev_data { + /* mutex for file operation*/ + struct mutex file_mutex; + /* main char dev structure */ + struct cdev main_dev; + + /* pointer to the corresponding RMI4 device. We use this to do */ + /* read, write, etc. */ + + struct platform_device *pdev; + struct clearpad_platform_data_t *pdata; + struct clearpad_bus_data_t *bdata; + /* reference count */ + int ref_count; + + struct class *device_class; + + unsigned char tmpbuf[RMI_CHAR_DEV_TMPBUF_SZ]; +}; + +/*store dynamically allocated major number of char device*/ +static int rmidev_major_num; + + +static struct class *rmidev_device_class; + +static int rmi_read_block(struct rmidev_data *data, u16 addr, u8 *buf, int len) +{ + return data->bdata->read_block(data->bdata->dev, addr, buf, len); +} + +static int rmi_write_block(struct rmidev_data *data, u16 addr, const u8 *buf, + int len) +{ + return data->bdata->write_block(data->bdata->dev, addr, buf, len); +} + +/* file operations for RMI char device */ + +/* + * rmidev_llseek: - use to setup register address + * + * @filp: file structure for seek + * @off: offset + * if whence == SEEK_SET, + * high 16 bits: page address + * low 16 bits: register address + * + * if whence == SEEK_CUR, + * offset from current position + * + * if whence == SEEK_END, + * offset from END(0xFFFF) + * + * @whence: SEEK_SET , SEEK_CUR or SEEK_END + */ +static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence) +{ + loff_t newpos; + struct rmidev_data *data = filp->private_data; + + if (IS_ERR(data)) { + pr_err("%s: pointer of char device is invalid", __func__); + newpos = -EBADF; + goto exit; + } + + mutex_lock(&(data->file_mutex)); + + switch (whence) { + case SEEK_SET: + newpos = off; + break; + + case SEEK_CUR: + newpos = filp->f_pos + off; + break; + + case SEEK_END: + newpos = REG_ADDR_LIMIT + off; + break; + + default: /* can't happen */ + newpos = -EINVAL; + goto clean_up; + } + + if (newpos < 0 || newpos > REG_ADDR_LIMIT) { + dev_err(&data->pdev->dev, "newpos 0x%04x is invalid.\n", + (unsigned int)newpos); + newpos = -EINVAL; + goto clean_up; + } + + filp->f_pos = newpos; + +clean_up: + mutex_unlock(&(data->file_mutex)); +exit: + return newpos; +} + +/* + * rmidev_read: - use to read data from RMI stream + * + * @filp: file structure for read + * @buf: user-level buffer pointer + * + * @count: number of byte read + * @f_pos: offset (starting register address) + * + * @return number of bytes read into user buffer (buf) if succeeds + * negative number if error occurs. + */ +static ssize_t rmidev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + struct rmidev_data *data = filp->private_data; + ssize_t retval = 0; + + if (*f_pos > REG_ADDR_LIMIT) { + retval = -EINVAL; + goto exit; + } + + /* limit offset to REG_ADDR_LIMIT-1 */ + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + if (count > RMI_CHAR_DEV_TMPBUF_SZ) + count = RMI_CHAR_DEV_TMPBUF_SZ; + + if (count == 0) + goto exit; + + if (IS_ERR(data)) { + pr_err("%s: pointer of char device is invalid", __func__); + retval = -EBADF; + goto exit; + } + + mutex_lock(&(data->file_mutex)); + + retval = rmi_read_block(data, *f_pos, data->tmpbuf, count); + + if (retval < 0) + goto clean_up; + else + *f_pos += retval; + + if (copy_to_user(buf, data->tmpbuf, count)) + retval = -EFAULT; + +clean_up: + + mutex_unlock(&(data->file_mutex)); +exit: + return retval; +} + +/* + * rmidev_write: - use to write data into RMI stream + * + * @filep : file structure for write + * @buf: user-level buffer pointer contains data to be written + * @count: number of byte be be written + * @f_pos: offset (starting register address) + * + * @return number of bytes written from user buffer (buf) if succeeds + * negative number if error occurs. + */ +static ssize_t rmidev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + struct rmidev_data *data = filp->private_data; + ssize_t retval = 0; + + if (*f_pos > REG_ADDR_LIMIT) { + retval = -EINVAL; + goto exit; + } + + /* limit offset to REG_ADDR_LIMIT-1 */ + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + if (count > RMI_CHAR_DEV_TMPBUF_SZ) + count = RMI_CHAR_DEV_TMPBUF_SZ; + + if (count == 0) + goto exit; + + if (IS_ERR(data)) { + pr_err("%s: pointer of char device is invalid", __func__); + retval = -EBADF; + goto exit; + } + + if (copy_from_user(data->tmpbuf, buf, count)) { + retval = -EFAULT; + goto exit; + } + + mutex_lock(&(data->file_mutex)); + + retval = rmi_write_block(data, *f_pos, data->tmpbuf, (int)count); + + if (retval >= 0) + *f_pos += count; + + mutex_unlock(&(data->file_mutex)); +exit: + return retval; +} + +/* + * rmidev_open: - get a new handle for from RMI stream + * @inp : inode struture + * @filp: file structure for read/write + * + * @return 0 if succeeds + */ +static int rmidev_open(struct inode *inp, struct file *filp) +{ + struct rmidev_data *data = container_of(inp->i_cdev, + struct rmidev_data, main_dev); + int retval = 0; + + filp->private_data = data; + + if (!data->pdata) { + retval = -EACCES; + goto exit; + } + + mutex_lock(&(data->file_mutex)); + if (data->ref_count < 1) + data->ref_count++; + else + retval = -EACCES; + + mutex_unlock(&(data->file_mutex)); +exit: + return retval; +} + +/* + * rmidev_release: - release an existing handle + * @inp: inode structure + * @filp: file structure for read/write + * + * @return 0 if succeeds + */ +static int rmidev_release(struct inode *inp, struct file *filp) +{ + struct rmidev_data *data = container_of(inp->i_cdev, + struct rmidev_data, main_dev); + int retval = 0; + + if (!data->pdev) { + retval = -EACCES; + goto exit; + } + + mutex_lock(&(data->file_mutex)); + + data->ref_count--; + if (data->ref_count < 0) + data->ref_count = 0; + + mutex_unlock(&(data->file_mutex)); +exit: + return retval; +} + +static const struct file_operations rmidev_fops = { + .owner = THIS_MODULE, + .llseek = rmidev_llseek, + .read = rmidev_read, + .write = rmidev_write, + .open = rmidev_open, + .release = rmidev_release, +}; + +/* + * rmi_char_dev_clean_up - release memory or unregister driver + * @rmi_char_dev: rmi_char_dev structure + * + */ +static void rmidev_device_cleanup(struct rmidev_data *data) +{ + dev_t devno; + + /* Get rid of our char dev entries */ + if (data) { + devno = data->main_dev.dev; + + if (data->device_class) + device_destroy(data->device_class, devno); + + cdev_del(&data->main_dev); + + /* cleanup_module is never called if registering failed */ + unregister_chrdev_region(devno, 1); + pr_debug("%s: rmidev device is removed\n", __func__); + } +} + +/* + * rmi_char_devnode - return device permission + * + * @dev: char device structure + * @mode: file permission + * + */ +static char *rmi_char_devnode(struct device *dev, umode_t *mode) +{ + char *pret = NULL; + + if (mode) { + /**mode = 0600*/ + *mode = S_IRUSR|S_IWUSR; + pret = kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev)); + } + return pret; +} + +static int rmidev_init_device(struct rmidev_data *data) +{ + dev_t dev_no; + int retval; + struct device *device_ptr; + + if (rmidev_major_num) { + dev_no = MKDEV(rmidev_major_num, 0); + retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME); + } else { + retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME); + /* let kernel allocate a major for us */ + rmidev_major_num = MAJOR(dev_no); + dev_info(&data->pdev->dev, "Major number of rmidev: %d\n", + rmidev_major_num); + } + if (retval < 0) { + dev_err(&data->pdev->dev, + "Failed to register or allocate char dev, code %d.\n", + retval); + goto exit; + } else { + dev_info(&data->pdev->dev, "Allocated rmidev %d %d.\n", + MAJOR(dev_no), MINOR(dev_no)); + } + + mutex_init(&data->file_mutex); + + cdev_init(&data->main_dev, &rmidev_fops); + + retval = cdev_add(&data->main_dev, dev_no, 1); + if (retval) { + dev_err(&data->pdev->dev, "Error %d adding rmi_char_dev.\n", + retval); + rmidev_device_cleanup(data); + goto exit; + } + + dev_set_name(&data->pdev->dev, "rmidev%d", MINOR(dev_no)); + data->device_class = rmidev_device_class; + device_ptr = device_create( + data->device_class, + NULL, dev_no, NULL, + CHAR_DEVICE_NAME"%d", + MINOR(dev_no)); + + if (IS_ERR(device_ptr)) { + dev_err(&data->pdev->dev, + "Failed to create rmi device.\n"); + rmidev_device_cleanup(data); + retval = -ENODEV; + } +exit: + return retval; +} + +static int rmi_dev_probe(struct platform_device *pdev) +{ + + struct clearpad_data_t *cdata = pdev->dev.platform_data; + struct rmidev_data *data; + int retval = 0; + + data = kzalloc(sizeof(struct rmidev_data), GFP_KERNEL); + if (!data) { + retval = -ENOMEM; + goto exit; + } + + dev_set_drvdata(&pdev->dev, data); + data->pdev = pdev; + data->pdata = cdata->pdata; + if (!data->pdata) { + dev_err(&data->pdev->dev, "no platform data\n"); + retval = -EINVAL; + goto err_free; + } + data->bdata = cdata->bdata; + if (!data->bdata) { + dev_err(&data->pdev->dev, "no bus data\n"); + retval = -EINVAL; + goto err_free; + } + + retval = rmidev_init_device(data); + if (!retval) + goto exit; + +err_free: + dev_set_drvdata(&pdev->dev, NULL); + kfree(data); +exit: + return retval; +} + +static int rmi_dev_remove(struct platform_device *pdev) +{ + struct rmidev_data *data = dev_get_drvdata(&pdev->dev); + dev_set_drvdata(&pdev->dev, NULL); + kfree(data); + return 0; +} + +static struct platform_driver rmidev_driver = { + .driver = { + .name = CLEARPAD_RMI_DEV_NAME, + .owner = THIS_MODULE, + }, + .probe = rmi_dev_probe, + .remove = rmi_dev_remove, +}; + +static int __init rmidev_init(void) +{ + int retval = 0; + + pr_debug("%s: rmi_dev initialization.\n", __func__); + + /* create device node */ + rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME); + + if (IS_ERR(rmidev_device_class)) { + pr_err("%s: ERROR - Failed to create /dev/%s.\n", __func__, + CHAR_DEVICE_NAME); + retval = -ENODEV; + goto exit; + } + /* setup permission */ + rmidev_device_class->devnode = rmi_char_devnode; + + retval = platform_driver_register(&rmidev_driver); +exit: + return retval; +} + +static void __exit rmidev_exit(void) +{ + pr_debug("%s: exiting.\n", __func__); + platform_driver_unregister(&rmidev_driver); + class_unregister(rmidev_device_class); + class_destroy(rmidev_device_class); +} + +module_init(rmidev_init); +module_exit(rmidev_exit); + +MODULE_AUTHOR("Christopher Heiny "); +MODULE_DESCRIPTION("RMI4 Char Device"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/st/fts.c b/drivers/input/touchscreen/st/fts.c index 08bfb83a94478b4cb11ce24c6129abfc0437c979..78bdd24af28b985bb614aaf43aed1ae019d02854 100644 --- a/drivers/input/touchscreen/st/fts.c +++ b/drivers/input/touchscreen/st/fts.c @@ -1003,10 +1003,7 @@ static unsigned char *fts_status_event_handler( case FTS_WATER_MODE_ON: case FTS_WATER_MODE_OFF: default: - logError(0, - "%s %s Received unhandled status event = %02X %02X %02X %02X %02X %02X %02X %02X\n", - tag, __func__, event[0], event[1], event[2], - event[3], event[4], event[5], event[6], event[7]); + logError(1, "%s %s Received unhandled status event = %02X %02X %02X %02X %02X %02X %02X %02X\n", tag, __func__, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]); break; } @@ -1758,6 +1755,8 @@ static int fts_fb_state_chg_callback(struct notifier_block *nb, unsigned long va info->resume_bit = 1; + fts_system_reset(); + fts_mode_handler(info, 0); info->sensor_sleep = false; @@ -1960,9 +1959,9 @@ static int parse_dt(struct device *dev, struct fts_i2c_platform_data *bdata) bdata->bus_reg_name = name; logError(0, "%s bus_reg_name = %s\n", tag, name); - if (of_property_read_bool(np, "st,reset-gpio")) { + if (of_property_read_bool(np, "st, reset-gpio")) { bdata->reset_gpio = of_get_named_gpio_flags(np, - "st,reset-gpio", 0, NULL); + "st, reset-gpio", 0, NULL); logError(0, "%s reset_gpio =%d\n", tag, bdata->reset_gpio); } else { bdata->reset_gpio = GPIO_NOT_DEFINED; @@ -2211,13 +2210,7 @@ static int fts_probe(struct i2c_client *client, } #endif - /*if wanna auto-update FW when probe, - * please don't comment the following code - */ - - /* queue_delayed_work(info->fwu_workqueue, &info->fwu_work, - * msecs_to_jiffies(EXP_FN_WORK_DELAY_MS)); - */ + queue_delayed_work(info->fwu_workqueue, &info->fwu_work, msecs_to_jiffies(EXP_FN_WORK_DELAY_MS)); logError(1, "%s Probe Finished!\n", tag); return OK; diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 94f1bf772ec93da011dae7415afb7316d25a2204..1c10273d17d4bb8805404150c5456b483fbcaa1d 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -16,6 +16,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index 22160e48179401cc6ab358cafcd7c4628cb214ea..4831eb910fc743b71cd1fc4e11a1c5732f989cdd 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c @@ -699,9 +699,9 @@ out_clear_state: out_unregister: mmu_notifier_unregister(&pasid_state->mn, mm); - mmput(mm); out_free: + mmput(mm); free_pasid_state(pasid_state); out: diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index ce18a512b76a908429155f7650ec35b207bf75fe..c6f74b1497063400a097b92e5ed1b82dd69854b5 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1727,8 +1727,7 @@ static void arm_smmu_pgtbl_unlock(struct arm_smmu_domain *smmu_domain, static int arm_smmu_restore_sec_cfg(struct arm_smmu_device *smmu) { - int ret; - u64 scm_ret; + int ret, scm_ret; if (!arm_smmu_is_static_cb(smmu)) return 0; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index f9711aceef54ceee4b2a56b47d15bea723d38a5c..b92b8a724efb8bcd35360ae530a1700821226b69 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1137,7 +1137,7 @@ static void dma_pte_free_level(struct dmar_domain *domain, int level, if (!dma_pte_present(pte) || dma_pte_superpage(pte)) goto next; - level_pfn = pfn & level_mask(level); + level_pfn = pfn & level_mask(level - 1); level_pte = phys_to_virt(dma_pte_addr(pte)); if (level > 2) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 92e6ae48caf82aaa7477c1b7cf80d9697453ed0d..33176a4aa6ef7ea5a29f1351e224815314ec9e08 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -394,30 +394,36 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev) device->dev = dev; ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group"); - if (ret) - goto err_free_device; + if (ret) { + kfree(device); + return ret; + } device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj)); rename: if (!device->name) { - ret = -ENOMEM; - goto err_remove_link; + sysfs_remove_link(&dev->kobj, "iommu_group"); + kfree(device); + return -ENOMEM; } ret = sysfs_create_link_nowarn(group->devices_kobj, &dev->kobj, device->name); if (ret) { + kfree(device->name); if (ret == -EEXIST && i >= 0) { /* * Account for the slim chance of collision * and append an instance to the name. */ - kfree(device->name); device->name = kasprintf(GFP_KERNEL, "%s.%d", kobject_name(&dev->kobj), i++); goto rename; } - goto err_free_name; + + sysfs_remove_link(&dev->kobj, "iommu_group"); + kfree(device); + return ret; } kobject_get(group->devices_kobj); @@ -429,10 +435,8 @@ rename: mutex_lock(&group->mutex); list_add_tail(&device->list, &group->devices); if (group->domain) - ret = __iommu_attach_device(group->domain, dev); + __iommu_attach_device(group->domain, dev); mutex_unlock(&group->mutex); - if (ret) - goto err_put_group; /* Notify any listeners about change to group. */ blocking_notifier_call_chain(&group->notifier, @@ -443,21 +447,6 @@ rename: pr_info("Adding device %s to group %d\n", dev_name(dev), group->id); return 0; - -err_put_group: - mutex_lock(&group->mutex); - list_del(&device->list); - mutex_unlock(&group->mutex); - dev->iommu_group = NULL; - kobject_put(group->devices_kobj); -err_free_name: - kfree(device->name); -err_remove_link: - sysfs_remove_link(&dev->kobj, "iommu_group"); -err_free_device: - kfree(device); - pr_err("Failed to add device %s to group %d: %d\n", dev_name(dev), group->id, ret); - return ret; } EXPORT_SYMBOL_GPL(iommu_group_add_device); diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 9e96d81bc5cdd888cacda2a9c7d718103005ba09..2e0f61a2dc3fda5ca88bf2b9ae87dc0c9f978f98 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -793,9 +793,6 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, int enabled; u64 val; - if (cpu >= nr_cpu_ids) - return -EINVAL; - if (gic_irq_in_rdist(d)) return -EINVAL; diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 620268b63b2a2117b8692d436d236c116a2faf5f..2f2ffb585bfc0c0f6515c2009d4b6a7f5e6d56a5 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -615,6 +615,13 @@ config LEDS_QPNP_WLED variable brightness. It also supports outputting the Avdd supply for AMOLED displays. +config LEDS_QPNP_RGB_SCALE + bool "Support for QPNP RGB LED brightness scale" + depends on LEDS_QPNP + default n + help + Adds kernel support for scaling the RGB LED brightness. + config LEDS_SYSCON bool "LED support for LEDs on system controllers" depends on LEDS_CLASS=y diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index ba20b8e42fbd687a2f24f16cf34be865977d963b..ca04ba69822e72000fbd7881510abccb21086130 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -8,6 +8,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 15c931bbbf65ccdef26024362c332768488521f3..103b5491eb756862a797dabbeddb2579d0623b0e 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "flashv2: %s: " fmt, __func__ @@ -158,11 +163,6 @@ #define FLASH_LED_DISABLE 0x00 #define FLASH_LED_SAFETY_TMR_DISABLED 0x13 #define FLASH_LED_MAX_TOTAL_CURRENT_MA 3750 -#define FLASH_LED_IRES5P0_MAX_CURR_MA 640 -#define FLASH_LED_IRES7P5_MAX_CURR_MA 960 -#define FLASH_LED_IRES10P0_MAX_CURR_MA 1280 -#define FLASH_LED_IRES12P5_MAX_CURR_MA 1600 -#define MAX_IRES_LEVELS 4 /* notifier call chain for flash-led irqs */ static ATOMIC_NOTIFIER_HEAD(irq_notifier_list); @@ -201,15 +201,14 @@ struct flash_node_data { struct pinctrl_state *hw_strobe_state_suspend; int hw_strobe_gpio; int ires_ua; - int default_ires_ua; int max_current; int current_ma; int prev_current_ma; u8 duration; + int duration_ms; u8 id; u8 type; - u8 ires_idx; - u8 default_ires_idx; + u8 ires; u8 hdrm_val; u8 current_reg_val; u8 strobe_ctrl; @@ -312,11 +311,6 @@ static int otst3_threshold_table[] = { 125, 119, 113, 107, 149, 143, 137, 131, }; -static int max_ires_curr_ma_table[MAX_IRES_LEVELS] = { - FLASH_LED_IRES12P5_MAX_CURR_MA, FLASH_LED_IRES10P0_MAX_CURR_MA, - FLASH_LED_IRES7P5_MAX_CURR_MA, FLASH_LED_IRES5P0_MAX_CURR_MA -}; - static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data) { int rc; @@ -947,7 +941,6 @@ static void qpnp_flash_led_aggregate_max_current(struct flash_node_data *fnode) static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value) { - int i = 0; int prgm_current_ma = value; int min_ma = fnode->ires_ua / 1000; struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev); @@ -957,22 +950,7 @@ static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value) else if (value < min_ma) prgm_current_ma = min_ma; - fnode->ires_idx = fnode->default_ires_idx; - fnode->ires_ua = fnode->default_ires_ua; - prgm_current_ma = min(prgm_current_ma, fnode->max_current); - if (prgm_current_ma > max_ires_curr_ma_table[fnode->ires_idx]) { - /* find the matching ires */ - for (i = MAX_IRES_LEVELS - 1; i >= 0; i--) { - if (prgm_current_ma <= max_ires_curr_ma_table[i]) { - fnode->ires_idx = i; - fnode->ires_ua = FLASH_LED_IRES_MIN_UA + - (FLASH_LED_IRES_BASE - fnode->ires_idx) * - FLASH_LED_IRES_DIVISOR; - break; - } - } - } fnode->current_ma = prgm_current_ma; fnode->cdev.brightness = prgm_current_ma; fnode->current_reg_val = CURRENT_MA_TO_REG_VAL(prgm_current_ma, @@ -1089,8 +1067,9 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) /* Iterate over all leds for this switch node */ val = 0; for (i = 0; i < led->num_fnodes; i++) - if (snode->led_mask & BIT(led->fnode[i].id)) - val |= led->fnode[i].ires_idx << (led->fnode[i].id * 2); + if (led->fnode[i].led_on && + snode->led_mask & BIT(led->fnode[i].id)) + val |= led->fnode[i].ires << (led->fnode[i].id * 2); rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_IRES(led->base), FLASH_LED_CURRENT_MASK, val); @@ -1306,9 +1285,149 @@ static ssize_t qpnp_flash_led_max_current_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", rc); } +/* sysfs show function for flash_led_fault_status */ +static ssize_t qpnp_flash_led_fault_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct flash_switch_data *snode; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_flash_led *led; + int rc; + uint val; + + snode = container_of(led_cdev, struct flash_switch_data, cdev); + led = dev_get_drvdata(&snode->pdev->dev); + + rc = regmap_read(led->regmap, + FLASH_LED_REG_LED_STATUS1(led->base), &val); + if (rc) { + pr_err("Unable to read fault status rc(%d)\n", rc); + return rc; + } + return scnprintf(buf, PAGE_SIZE, "%d\n", val); +} + +/* sysfs store function for flash strobe */ +static ssize_t qpnp_flash_led_strobe_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct flash_node_data *fnode; + unsigned long state; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + + ret = kstrtoul(buf, 10, &state); + if (ret) + return ret; + + fnode = container_of(led_cdev, struct flash_node_data, cdev); + + /* '0' for sw strobe; '1' for hw strobe */ + if (state == 1) + fnode->strobe_ctrl |= FLASH_LED_HW_SW_STROBE_SEL_BIT; + else + fnode->strobe_ctrl &= ~FLASH_LED_HW_SW_STROBE_SEL_BIT; + + return count; +} + +/* sysfs show function for flash duration */ +static ssize_t qpnp_flash_led_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qpnp_flash_led *led; + struct flash_node_data *flash_node; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + flash_node = container_of(led_cdev, struct flash_node_data, cdev); + led = dev_get_drvdata(&flash_node->pdev->dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", flash_node->duration_ms); +} + +/* sysfs store function for flash duration */ +static ssize_t qpnp_flash_led_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_flash_led *led; + struct flash_node_data *flash_node; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + ssize_t ret; + unsigned long state; + + flash_node = container_of(led_cdev, struct flash_node_data, cdev); + led = dev_get_drvdata(&flash_node->pdev->dev); + + ret = kstrtoul(buf, 10, &state); + if (ret) + return ret; + + flash_node->duration_ms = state; + flash_node->duration = (u8)(SAFETY_TMR_TO_REG_VAL(flash_node->duration_ms) | + FLASH_LED_SAFETY_TMR_ENABLE); + + return count; +} + +/* sysfs show function for flash ires_ua */ +static ssize_t qpnp_flash_led_ires_ua_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qpnp_flash_led *led; + struct flash_node_data *flash_node; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + flash_node = container_of(led_cdev, struct flash_node_data, cdev); + led = dev_get_drvdata(&flash_node->pdev->dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", flash_node->ires_ua); +} + +/* sysfs store function for flash ires_ua */ +static ssize_t qpnp_flash_led_ires_ua_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_flash_led *led; + struct flash_node_data *flash_node; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + ssize_t ret; + unsigned long state; + + flash_node = container_of(led_cdev, struct flash_node_data, cdev); + led = dev_get_drvdata(&flash_node->pdev->dev); + + ret = kstrtoul(buf, 10, &state); + if (ret) + return ret; + + flash_node->ires_ua = state; + flash_node->ires = FLASH_LED_IRES_BASE - + (flash_node->ires_ua - FLASH_LED_IRES_MIN_UA) / FLASH_LED_IRES_DIVISOR; + + return count; +} + /* sysfs attributes exported by flash_led */ static struct device_attribute qpnp_flash_led_attrs[] = { __ATTR(max_current, 0664, qpnp_flash_led_max_current_show, NULL), + __ATTR(fault_status, S_IRUSR | S_IRGRP, + qpnp_flash_led_fault_status_show, + NULL), +}; + +static struct device_attribute qpnp_flash_fnode_attrs[] = { + __ATTR(strobe, (S_IRUGO | S_IWUSR | S_IWGRP), + NULL, + qpnp_flash_led_strobe_type_store), + __ATTR(duration, (S_IRUGO | S_IWUSR | S_IWGRP), + qpnp_flash_led_duration_show, + qpnp_flash_led_duration_store), + __ATTR(ires_ua, (S_IRUGO | S_IWUSR | S_IWGRP), + qpnp_flash_led_ires_ua_show, + qpnp_flash_led_ires_ua_store), }; static int flash_led_psy_notifier_call(struct notifier_block *nb, @@ -1462,14 +1581,13 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, return rc; } - fnode->default_ires_ua = fnode->ires_ua = FLASH_LED_IRES_DEFAULT_UA; - fnode->default_ires_idx = fnode->ires_idx = FLASH_LED_IRES_DEFAULT_VAL; + fnode->ires_ua = FLASH_LED_IRES_DEFAULT_UA; + fnode->ires = FLASH_LED_IRES_DEFAULT_VAL; rc = of_property_read_u32(node, "qcom,ires-ua", &val); if (!rc) { - fnode->default_ires_ua = fnode->ires_ua = val; - fnode->default_ires_idx = fnode->ires_idx = - FLASH_LED_IRES_BASE - (val - FLASH_LED_IRES_MIN_UA) / - FLASH_LED_IRES_DIVISOR; + fnode->ires_ua = val; + fnode->ires = FLASH_LED_IRES_BASE - + (val - FLASH_LED_IRES_MIN_UA) / FLASH_LED_IRES_DIVISOR; } else if (rc != -EINVAL) { pr_err("Unable to read current resolution rc=%d\n", rc); return rc; @@ -1505,6 +1623,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, fnode->duration = FLASH_LED_SAFETY_TMR_DISABLED; rc = of_property_read_u32(node, "qcom,duration-ms", &val); if (!rc) { + fnode->duration_ms = val; fnode->duration = (u8)(SAFETY_TMR_TO_REG_VAL(val) | FLASH_LED_SAFETY_TMR_ENABLE); } else if (rc == -EINVAL) { @@ -1577,7 +1696,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, "qcom,hw-strobe-edge-trigger"); active_high = !of_property_read_bool(node, "qcom,hw-strobe-active-low"); - hw_strobe = 1; + hw_strobe = !of_property_read_bool(node, "somc,sw-strobe-init"); } else if (fnode->strobe_sel == LPG_STROBE) { /* LPG strobe requires level trigger and active high */ edge_trigger = 0; @@ -1680,7 +1799,8 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, if (IS_ERR_OR_NULL(snode->vreg)) { rc = PTR_ERR(snode->vreg); if (rc != -EPROBE_DEFER) - pr_err("Failed to get regulator, rc=%d\n", rc); + dev_err(&led->pdev->dev, "Failed to get regulator, rc=%d\n", + rc); snode->vreg = NULL; return rc; } @@ -2139,6 +2259,29 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, return 0; } +static int qpnp_flash_led_init_strobe_settings(struct qpnp_flash_led *led) +{ + int rc = 0, i, addr_offset; + + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_STROBE_CFG(led->base), + FLASH_LED_STROBE_MASK, + led->pdata->hw_strobe_option); + if (rc < 0) + return rc; + + for (i = 0; i < led->num_fnodes; i++) { + addr_offset = led->fnode[i].id; + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset), + FLASH_LED_STROBE_MASK, led->fnode[i].strobe_ctrl); + if (rc < 0) + return rc; + } + + return rc; +} + static int qpnp_flash_led_probe(struct platform_device *pdev) { struct qpnp_flash_led *led; @@ -2308,6 +2451,23 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) goto unreg_notifier; } + rc = qpnp_flash_led_init_strobe_settings(led); + if (rc < 0) { + pr_err("Failed to initialize flash strobe, rc=%d\n", rc); + goto unreg_notifier; + } + + for (i = 0; i < led->num_fnodes; i++) { + for (j = 0; j < ARRAY_SIZE(qpnp_flash_fnode_attrs); j++) { + rc = sysfs_create_file(&led->fnode[i].cdev.dev->kobj, + &qpnp_flash_fnode_attrs[j].attr); + if (rc < 0) { + pr_err("sysfs creation failed, rc=%d\n", rc); + goto sysfs_fnode_fail; + } + } + } + for (i = 0; i < led->num_snodes; i++) { for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) { rc = sysfs_create_file(&led->snode[i].cdev.dev->kobj, @@ -2325,6 +2485,16 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) return 0; +sysfs_fnode_fail: + for (--j; j >= 0; j--) + sysfs_remove_file(&led->fnode[i].cdev.dev->kobj, + &qpnp_flash_fnode_attrs[j].attr); + + for (--i; i >= 0; i--) { + for (j = 0; j < ARRAY_SIZE(qpnp_flash_fnode_attrs); j++) + sysfs_remove_file(&led->fnode[i].cdev.dev->kobj, + &qpnp_flash_fnode_attrs[j].attr); + } sysfs_fail: for (--j; j >= 0; j--) sysfs_remove_file(&led->snode[i].cdev.dev->kobj, @@ -2335,7 +2505,6 @@ sysfs_fail: sysfs_remove_file(&led->snode[i].cdev.dev->kobj, &qpnp_flash_led_attrs[j].attr); } - i = led->num_snodes; unreg_notifier: power_supply_unreg_notifier(&led->nb); @@ -2369,6 +2538,13 @@ static int qpnp_flash_led_remove(struct platform_device *pdev) led_classdev_unregister(&led->snode[--i].cdev); i = led->num_fnodes; + + for (i = 0; i < led->num_fnodes; i++) { + for (j = 0; j < ARRAY_SIZE(qpnp_flash_fnode_attrs); j++) + sysfs_remove_file(&led->fnode[i].cdev.dev->kobj, + &qpnp_flash_fnode_attrs[j].attr); + } + while (i > 0) led_classdev_unregister(&led->fnode[--i].cdev); diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index bfa7d29701dadd73bacbc8ff810aca1f7619f70a..fba97c2e90e11e6bca366693f0ca9920bc27533f 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -160,19 +165,18 @@ #define QPNP_WLED_MOD_EN_SHFT 7 #define QPNP_WLED_MOD_EN 1 #define QPNP_WLED_GATE_DRV_MASK 0xFE -#define QPNP_WLED_SYNC_DLY_MASK GENMASK(2, 0) +#define QPNP_WLED_SYNC_DLY_MASK 0xF8 #define QPNP_WLED_SYNC_DLY_MIN_US 0 #define QPNP_WLED_SYNC_DLY_MAX_US 1400 #define QPNP_WLED_SYNC_DLY_STEP_US 200 #define QPNP_WLED_DEF_SYNC_DLY_US 400 -#define QPNP_WLED_FS_CURR_MASK GENMASK(3, 0) +#define QPNP_WLED_FS_CURR_MASK 0xF0 #define QPNP_WLED_FS_CURR_MIN_UA 0 #define QPNP_WLED_FS_CURR_MAX_UA 30000 #define QPNP_WLED_FS_CURR_STEP_UA 2500 -#define QPNP_WLED_CABC_MASK 0x80 +#define QPNP_WLED_CABC_MASK 0x7F #define QPNP_WLED_CABC_SHIFT 7 #define QPNP_WLED_CURR_SINK_SHIFT 4 -#define QPNP_WLED_CURR_SINK_MASK GENMASK(7, 4) #define QPNP_WLED_BRIGHT_LSB_MASK 0xFF #define QPNP_WLED_BRIGHT_MSB_SHIFT 8 #define QPNP_WLED_BRIGHT_MSB_MASK 0x0F @@ -209,14 +213,12 @@ #define QPNP_WLED_SEC_UNLOCK 0xA5 #define QPNP_WLED_MAX_STRINGS 4 -#define QPNP_PM660_WLED_MAX_STRINGS 3 #define WLED_MAX_LEVEL_4095 4095 #define QPNP_WLED_RAMP_DLY_MS 20 #define QPNP_WLED_TRIGGER_NONE "none" #define QPNP_WLED_STR_SIZE 20 #define QPNP_WLED_MIN_MSLEEP 20 #define QPNP_WLED_SC_DLY_MS 20 -#define QPNP_WLED_SOFT_START_DLY_US 10000 #define NUM_SUPPORTED_AVDD_VOLTAGES 6 #define QPNP_WLED_DFLT_AVDD_MV 7600 @@ -234,6 +236,13 @@ #define QPNP_WLED_AVDD_MV_TO_REG(val) \ ((val - QPNP_WLED_AVDD_MIN_MV) / QPNP_WLED_AVDD_STEP_MV) +#define QPNP_WLED_CURR_SCALE_MAX 100 +#define QPNP_WLED_BL_SCALE_MAX 1000 +#define QPNP_WLED_BUFF_SIZE 128 + +#define BR_MAX_FIGURE 9 +#define AREA_COUNT_MAX 9999999 + /* output feedback mode */ enum qpnp_wled_fdbk_op { QPNP_WLED_FDBK_AUTO, @@ -308,6 +317,12 @@ static struct wled_vref_setting vref_setting_pmi8998 = { 60000, 397500, 22500, 127500, }; +static unsigned long *area_count; +static int *area_count_table; +static int area_count_table_size; +static int now_area; +static unsigned long start_jiffies; + /** * qpnp_wled - wed data structure * @ cdev - led class device @@ -384,8 +399,6 @@ struct qpnp_wled { u16 ramp_ms; u16 ramp_step; u16 cons_sync_write_delay_us; - u16 auto_calibration_ovp_count; - u16 max_strings; u8 strings[QPNP_WLED_MAX_STRINGS]; u8 num_strings; u8 loop_auto_gm_thresh; @@ -401,11 +414,24 @@ struct qpnp_wled { bool en_ext_pfet_sc_pro; bool prev_state; bool ovp_irq_disabled; - bool auto_calib_enabled; - bool auto_calib_done; - ktime_t start_ovp_fault_time; + int init_br_ua; + bool bl_scale_enabled; + int bl_scale; + bool calc_curr; + int curr_scale; }; +static bool bl_on_in_boot; +static int __init continous_splash_setup(char *str) +{ + if (!str) + return 0; + if (!strncmp(str, "on", 2)) + bl_on_in_boot = true; + return 0; +} +__setup("display_status=", continous_splash_setup); + /* helper to read a pmic register */ static int qpnp_wled_read_reg(struct qpnp_wled *wled, u16 addr, u8 *data) { @@ -538,8 +564,18 @@ static int qpnp_wled_set_level(struct qpnp_wled *wled, int level) int i, rc; u8 reg; + if (wled->calc_curr && + wled->curr_scale != QPNP_WLED_CURR_SCALE_MAX) + level = level * wled->curr_scale / QPNP_WLED_CURR_SCALE_MAX; + + if (wled->bl_scale_enabled && wled->bl_scale > 0 && + wled->bl_scale < QPNP_WLED_BL_SCALE_MAX) + level = level * wled->bl_scale / QPNP_WLED_BL_SCALE_MAX; + + pr_debug("%s: brightness=%d level=%d\n", + __func__, wled->cdev.brightness, level); /* set brightness registers */ - for (i = 0; i < wled->max_strings; i++) { + for (i = 0; i < wled->num_strings; i++) { reg = level & QPNP_WLED_BRIGHT_LSB_MASK; rc = qpnp_wled_write_reg(wled, QPNP_WLED_BRIGHT_LSB_REG(wled->sink_base, @@ -608,8 +644,7 @@ static int qpnp_wled_module_en(struct qpnp_wled *wled, * OVP interrupt disabled when the module is disabled. */ if (state) { - usleep_range(QPNP_WLED_SOFT_START_DLY_US, - QPNP_WLED_SOFT_START_DLY_US + 1000); + usleep_range(10000, 11000); rc = qpnp_wled_psm_config(wled, false); if (rc < 0) return rc; @@ -882,25 +917,36 @@ static ssize_t qpnp_wled_fs_curr_ua_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qpnp_wled *wled = dev_get_drvdata(dev); - int data, i, rc; + int data, i, rc, temp; u8 reg; rc = kstrtoint(buf, 10, &data); if (rc) return rc; - for (i = 0; i < wled->max_strings; i++) { + for (i = 0; i < wled->num_strings; i++) { if (data < QPNP_WLED_FS_CURR_MIN_UA) data = QPNP_WLED_FS_CURR_MIN_UA; else if (data > QPNP_WLED_FS_CURR_MAX_UA) data = QPNP_WLED_FS_CURR_MAX_UA; - reg = data / QPNP_WLED_FS_CURR_STEP_UA; - rc = qpnp_wled_masked_write_reg(wled, - QPNP_WLED_FS_CURR_REG(wled->sink_base, i), - QPNP_WLED_FS_CURR_MASK, reg); + rc = qpnp_wled_read_reg(wled, + QPNP_WLED_FS_CURR_REG(wled->sink_base, + wled->strings[i]), ®); if (rc < 0) return rc; + reg &= QPNP_WLED_FS_CURR_MASK; + if (wled->calc_curr) + temp = (data + (QPNP_WLED_FS_CURR_STEP_UA - 1)) / + QPNP_WLED_FS_CURR_STEP_UA; + else + temp = data / QPNP_WLED_FS_CURR_STEP_UA; + reg |= temp; + rc = qpnp_wled_write_reg(wled, + QPNP_WLED_FS_CURR_REG(wled->sink_base, + wled->strings[i]), reg); + if (rc) + return rc; } wled->fs_curr_ua = data; @@ -914,6 +960,101 @@ static ssize_t qpnp_wled_fs_curr_ua_store(struct device *dev, return count; } +static ssize_t qpnp_wled_bl_scale_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qpnp_wled *wled = dev_get_drvdata(dev); + if (!wled->bl_scale_enabled) + wled->bl_scale = QPNP_WLED_BL_SCALE_MAX; + dev_dbg(&wled->pdev->dev, "%s: bl_scale = %d\n", __func__, wled->bl_scale); + + return snprintf(buf, QPNP_WLED_BUFF_SIZE, "%u\n", wled->bl_scale); +} + +static ssize_t qpnp_wled_bl_scale_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct qpnp_wled *wled = dev_get_drvdata(dev); + unsigned long scale = 0; + ssize_t ret = -EINVAL; + + if (!wled->bl_scale_enabled) { + wled->bl_scale = QPNP_WLED_BL_SCALE_MAX; + dev_err(&wled->pdev->dev, "Sysfs bl_scale is not enabled\n"); + goto exit; + } + + ret = kstrtoul(buf, 10, &scale); + if (!ret) { + ret = size; + if (scale > QPNP_WLED_BL_SCALE_MAX) + scale = QPNP_WLED_BL_SCALE_MAX; + wled->bl_scale = scale; + dev_dbg(&wled->pdev->dev, "%s: bl_scale = %d\n", __func__, wled->bl_scale); + } else { + dev_err(&wled->pdev->dev, "Failure to set sysfs bl_scale\n"); + ret = -EINVAL; + } + +exit: + return ret; +} + +static void update_areacount(int new_area) +{ + unsigned long now; + unsigned long duration; + + now = jiffies; + duration = (now - start_jiffies) >= 0 ? + (now - start_jiffies) : (now + start_jiffies); + area_count[now_area] = area_count[now_area] + + jiffies_to_msecs(duration); + + now_area = new_area; + start_jiffies = now; +} + +static ssize_t qpnp_wled_area_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qpnp_wled *wled = dev_get_drvdata(dev); + int i; + char area_count_str[QPNP_WLED_BUFF_SIZE]; + char count_data[BR_MAX_FIGURE]; + + if (!area_count_table_size) + return snprintf(buf, QPNP_WLED_BUFF_SIZE, "area_count is not supported\n"); + + mutex_lock(&wled->cdev.led_access); + /* fixed statistics */ + update_areacount(now_area); + + memset(area_count_str, 0, sizeof(char) * QPNP_WLED_BUFF_SIZE); + for (i = 0; i < area_count_table_size; i++) { + dev_dbg(&wled->pdev->dev, "%ld, ", area_count[i]); + memset(count_data, 0, sizeof(char) * BR_MAX_FIGURE); + if (area_count[i] > AREA_COUNT_MAX) { + /* over 167 min */ + area_count[i] = AREA_COUNT_MAX; + } + if (i == 0) { + snprintf(count_data, BR_MAX_FIGURE, + "%ld", area_count[i]); + strlcpy(area_count_str, count_data, QPNP_WLED_BUFF_SIZE); + } else { + snprintf(count_data, BR_MAX_FIGURE, + ",%ld", area_count[i]); + strlcat(area_count_str, count_data, QPNP_WLED_BUFF_SIZE); + } + } + + memset(area_count, 0, sizeof(unsigned long) * area_count_table_size); + mutex_unlock(&wled->cdev.led_access); + + return snprintf(buf, QPNP_WLED_BUFF_SIZE, "%s\n", area_count_str); +} + /* sysfs attributes exported by wled */ static struct device_attribute qpnp_wled_attrs[] = { __ATTR(dump_regs, 0664, qpnp_wled_dump_regs_show, NULL), @@ -925,8 +1066,39 @@ static struct device_attribute qpnp_wled_attrs[] = { __ATTR(ramp_ms, 0664, qpnp_wled_ramp_ms_show, qpnp_wled_ramp_ms_store), __ATTR(ramp_step, 0664, qpnp_wled_ramp_step_show, qpnp_wled_ramp_step_store), + __ATTR(bl_scale, (S_IRUGO | S_IWUSR | S_IWGRP), + qpnp_wled_bl_scale_show, + qpnp_wled_bl_scale_store), + __ATTR(area_count, (S_IRUSR | S_IRGRP), + qpnp_wled_area_count_show, + NULL), }; +static int get_area(int level) +{ + int i; + + for (i = 0; i < area_count_table_size; i++) { + if (i == 0) { + if (level == area_count_table[i]) + break; + } else { + if (level <= area_count_table[i]) + break; + } + } + + return i; +} + +static void qpnp_wled_update_area(int level) +{ + int new_area = get_area(level); + + if (now_area != new_area) + update_areacount(new_area); +} + /* worker for setting wled brightness */ static void qpnp_wled_work(struct work_struct *work) { @@ -936,6 +1108,7 @@ static void qpnp_wled_work(struct work_struct *work) wled = container_of(work, struct qpnp_wled, work); level = wled->cdev.brightness; + qpnp_wled_update_area(level); mutex_lock(&wled->lock); @@ -967,6 +1140,7 @@ static void qpnp_wled_work(struct work_struct *work) level ? "en" : "dis"); goto unlock_mutex; } + usleep_range(100, 101); } wled->prev_state = !!level; @@ -1092,229 +1266,6 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr) return 0; } -#define AUTO_CALIB_BRIGHTNESS 16 -static int wled_auto_calibrate(struct qpnp_wled *wled) -{ - int rc = 0, i; - u8 reg = 0, sink_config = 0, sink_test = 0, sink_valid = 0, int_sts; - - mutex_lock(&wled->lock); - - /* disable OVP IRQ */ - if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) { - disable_irq_nosync(wled->ovp_irq); - wled->ovp_irq_disabled = true; - } - - /* read configured sink configuration */ - rc = qpnp_wled_read_reg(wled, - QPNP_WLED_CURR_SINK_REG(wled->sink_base), &sink_config); - if (rc < 0) { - pr_err("Failed to read SINK configuration rc=%d\n", rc); - goto failed_calib; - } - - /* disable the module before starting calibration */ - rc = qpnp_wled_masked_write_reg(wled, - QPNP_WLED_MODULE_EN_REG(wled->ctrl_base), - QPNP_WLED_MODULE_EN_MASK, 0); - if (rc < 0) { - pr_err("Failed to disable WLED module rc=%d\n", rc); - goto failed_calib; - } - - /* set low brightness across all sinks */ - rc = qpnp_wled_set_level(wled, AUTO_CALIB_BRIGHTNESS); - if (rc < 0) { - pr_err("Failed to set brightness for calibration rc=%d\n", rc); - goto failed_calib; - } - - /* disable all sinks */ - rc = qpnp_wled_write_reg(wled, - QPNP_WLED_CURR_SINK_REG(wled->sink_base), 0); - if (rc < 0) { - pr_err("Failed to disable all sinks rc=%d\n", rc); - goto failed_calib; - } - - rc = qpnp_wled_masked_write_reg(wled, - QPNP_WLED_MODULE_EN_REG(wled->ctrl_base), - QPNP_WLED_MODULE_EN_MASK, - QPNP_WLED_MODULE_EN_MASK); - if (rc < 0) { - pr_err("Failed to enable WLED module rc=%d\n", rc); - goto failed_calib; - } - /* - * Delay for the WLED soft-start, check the OVP status - * only after soft-start is complete - */ - usleep_range(QPNP_WLED_SOFT_START_DLY_US, - QPNP_WLED_SOFT_START_DLY_US + 1000); - - /* iterate through the strings one by one */ - for (i = 0; i < wled->max_strings; i++) { - sink_test = 1 << (QPNP_WLED_CURR_SINK_SHIFT + i); - - /* Enable feedback control */ - rc = qpnp_wled_write_reg(wled, - QPNP_WLED_FDBK_OP_REG(wled->ctrl_base), - i + 1); - if (rc < 0) { - pr_err("Failed to enable feedback for SINK %d rc = %d\n", - i + 1, rc); - goto failed_calib; - } - - /* enable the sink */ - rc = qpnp_wled_write_reg(wled, - QPNP_WLED_CURR_SINK_REG(wled->sink_base), sink_test); - if (rc < 0) { - pr_err("Failed to configure SINK %d rc=%d\n", - i + 1, rc); - goto failed_calib; - } - - /* delay for WLED soft-start */ - usleep_range(QPNP_WLED_SOFT_START_DLY_US, - QPNP_WLED_SOFT_START_DLY_US + 1000); - - rc = qpnp_wled_read_reg(wled, - QPNP_WLED_INT_RT_STS(wled->ctrl_base), &int_sts); - if (rc < 0) { - pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc); - goto failed_calib; - } - - if (int_sts & QPNP_WLED_OVP_FAULT_BIT) - pr_debug("WLED OVP fault detected with SINK %d\n", - i + 1); - else - sink_valid |= sink_test; - } - - if (sink_valid == sink_config) { - pr_debug("WLED auto-calibration complete, default sink-config=%x OK!\n", - sink_config); - } else { - pr_warn("Invalid WLED default sink config=%x changing it to=%x\n", - sink_config, sink_valid); - sink_config = sink_valid; - } - - if (!sink_config) { - pr_warn("No valid WLED sinks found\n"); - goto failed_calib; - } - - rc = qpnp_wled_masked_write_reg(wled, - QPNP_WLED_MODULE_EN_REG(wled->ctrl_base), - QPNP_WLED_MODULE_EN_MASK, 0); - if (rc < 0) { - pr_err("Failed to disable WLED module rc=%d\n", rc); - goto failed_calib; - } - - /* write the new sink configuration */ - rc = qpnp_wled_write_reg(wled, - QPNP_WLED_CURR_SINK_REG(wled->sink_base), sink_config); - if (rc < 0) { - pr_err("Failed to reconfigure the default sink rc=%d\n", rc); - goto failed_calib; - } - - /* MODULATOR_EN setting for valid sinks */ - for (i = 0; i < wled->max_strings; i++) { - if (sink_config & (1 << (QPNP_WLED_CURR_SINK_SHIFT + i))) - reg = (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT); - else - reg = 0x0; /* disable modulator_en for unused sink */ - - if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) - reg &= QPNP_WLED_GATE_DRV_MASK; - else - reg |= ~QPNP_WLED_GATE_DRV_MASK; - - rc = qpnp_wled_write_reg(wled, - QPNP_WLED_MOD_EN_REG(wled->sink_base, i), reg); - if (rc < 0) { - pr_err("Failed to configure MODULATOR_EN rc=%d\n", rc); - goto failed_calib; - } - } - - /* restore the feedback setting */ - rc = qpnp_wled_write_reg(wled, - QPNP_WLED_FDBK_OP_REG(wled->ctrl_base), - wled->fdbk_op); - if (rc < 0) { - pr_err("Failed to restore feedback setting rc=%d\n", rc); - goto failed_calib; - } - - /* restore brightness */ - rc = qpnp_wled_set_level(wled, wled->cdev.brightness); - if (rc < 0) { - pr_err("Failed to set brightness after calibration rc=%d\n", - rc); - goto failed_calib; - } - - rc = qpnp_wled_masked_write_reg(wled, - QPNP_WLED_MODULE_EN_REG(wled->ctrl_base), - QPNP_WLED_MODULE_EN_MASK, - QPNP_WLED_MODULE_EN_MASK); - if (rc < 0) { - pr_err("Failed to enable WLED module rc=%d\n", rc); - goto failed_calib; - } - - /* delay for WLED soft-start */ - usleep_range(QPNP_WLED_SOFT_START_DLY_US, - QPNP_WLED_SOFT_START_DLY_US + 1000); - -failed_calib: - if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) { - enable_irq(wled->ovp_irq); - wled->ovp_irq_disabled = false; - } - mutex_unlock(&wled->lock); - return rc; -} - -#define WLED_AUTO_CAL_OVP_COUNT 5 -#define WLED_AUTO_CAL_CNT_DLY_US 1000000 /* 1 second */ -static bool qpnp_wled_auto_cal_required(struct qpnp_wled *wled) -{ - s64 elapsed_time_us; - - /* - * Check if the OVP fault was an occasional one - * or if its firing continuously, the latter qualifies - * for an auto-calibration check. - */ - if (!wled->auto_calibration_ovp_count) { - wled->start_ovp_fault_time = ktime_get(); - wled->auto_calibration_ovp_count++; - } else { - elapsed_time_us = ktime_us_delta(ktime_get(), - wled->start_ovp_fault_time); - if (elapsed_time_us > WLED_AUTO_CAL_CNT_DLY_US) - wled->auto_calibration_ovp_count = 0; - else - wled->auto_calibration_ovp_count++; - - if (wled->auto_calibration_ovp_count >= - WLED_AUTO_CAL_OVP_COUNT) { - wled->auto_calibration_ovp_count = 0; - return true; - } - } - - return false; -} - /* ovp irq handler */ static irqreturn_t qpnp_wled_ovp_irq_handler(int irq, void *_wled) { @@ -1339,21 +1290,6 @@ static irqreturn_t qpnp_wled_ovp_irq_handler(int irq, void *_wled) if (fault_sts & (QPNP_WLED_OVP_FAULT_BIT | QPNP_WLED_ILIM_FAULT_BIT)) pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n", int_sts, fault_sts); - - if (fault_sts & QPNP_WLED_OVP_FAULT_BIT) { - if (wled->auto_calib_enabled && !wled->auto_calib_done) { - if (qpnp_wled_auto_cal_required(wled)) { - rc = wled_auto_calibrate(wled); - if (rc < 0) { - pr_err("Failed auto-calibration rc=%d\n", - rc); - return IRQ_HANDLED; - } - wled->auto_calib_done = true; - } - } - } - return IRQ_HANDLED; } @@ -1663,7 +1599,7 @@ static int qpnp_wled_vref_config(struct qpnp_wled *wled) static int qpnp_wled_config(struct qpnp_wled *wled) { int rc, i, temp; - u8 reg = 0, sink_en = 0, mask; + u8 reg = 0; /* Configure display type */ rc = qpnp_wled_set_disp(wled, wled->ctrl_base); @@ -1857,82 +1793,104 @@ static int qpnp_wled_config(struct qpnp_wled *wled) if (rc) return rc; - /* disable all current sinks and enable selected strings */ - reg = 0x00; - rc = qpnp_wled_write_reg(wled, QPNP_WLED_CURR_SINK_REG(wled->sink_base), - reg); + if (!bl_on_in_boot) { + /* disable all current sinks and enable selected strings */ + reg = 0x00; + rc = qpnp_wled_write_reg(wled, QPNP_WLED_CURR_SINK_REG(wled->sink_base), + reg); - for (i = 0; i < wled->max_strings; i++) { - /* SYNC DELAY */ - if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US) - wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US; + for (i = 0; i < wled->num_strings; i++) { + if (wled->strings[i] >= QPNP_WLED_MAX_STRINGS) { + dev_err(&wled->pdev->dev, "Invalid string number\n"); + return -EINVAL; + } - reg = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US; - mask = QPNP_WLED_SYNC_DLY_MASK; - rc = qpnp_wled_masked_write_reg(wled, - QPNP_WLED_SYNC_DLY_REG(wled->sink_base, i), - mask, reg); - if (rc < 0) - return rc; + /* MODULATOR */ + rc = qpnp_wled_read_reg(wled, + QPNP_WLED_MOD_EN_REG(wled->sink_base, + wled->strings[i]), ®); + if (rc < 0) + return rc; + reg &= QPNP_WLED_MOD_EN_MASK; + reg |= (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT); - /* FULL SCALE CURRENT */ - if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA) - wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA; + if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) + reg &= QPNP_WLED_GATE_DRV_MASK; + else + reg |= ~QPNP_WLED_GATE_DRV_MASK; - reg = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA; - mask = QPNP_WLED_FS_CURR_MASK; - rc = qpnp_wled_masked_write_reg(wled, - QPNP_WLED_FS_CURR_REG(wled->sink_base, i), - mask, reg); - if (rc < 0) - return rc; + rc = qpnp_wled_write_reg(wled, + QPNP_WLED_MOD_EN_REG(wled->sink_base, + wled->strings[i]), reg); + if (rc) + return rc; - /* CABC */ - reg = wled->en_cabc ? (1 << QPNP_WLED_CABC_SHIFT) : 0; - mask = QPNP_WLED_CABC_MASK; - rc = qpnp_wled_masked_write_reg(wled, - QPNP_WLED_CABC_REG(wled->sink_base, i), - mask, reg); - if (rc < 0) - return rc; - } + /* SYNC DELAY */ + if (wled->sync_dly_us > QPNP_WLED_SYNC_DLY_MAX_US) + wled->sync_dly_us = QPNP_WLED_SYNC_DLY_MAX_US; - /* Settings specific to valid sinks */ - for (i = 0; i < wled->num_strings; i++) { - if (wled->strings[i] >= wled->max_strings) { - dev_err(&wled->pdev->dev, "Invalid string number\n"); - return -EINVAL; - } - /* MODULATOR */ - rc = qpnp_wled_read_reg(wled, - QPNP_WLED_MOD_EN_REG(wled->sink_base, i), ®); - if (rc < 0) - return rc; - reg &= QPNP_WLED_MOD_EN_MASK; - reg |= (QPNP_WLED_MOD_EN << QPNP_WLED_MOD_EN_SHFT); + rc = qpnp_wled_read_reg(wled, + QPNP_WLED_SYNC_DLY_REG(wled->sink_base, + wled->strings[i]), ®); + if (rc < 0) + return rc; + reg &= QPNP_WLED_SYNC_DLY_MASK; + temp = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US; + reg |= temp; + rc = qpnp_wled_write_reg(wled, + QPNP_WLED_SYNC_DLY_REG(wled->sink_base, + wled->strings[i]), reg); + if (rc) + return rc; - if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) - reg &= QPNP_WLED_GATE_DRV_MASK; - else - reg |= ~QPNP_WLED_GATE_DRV_MASK; + /* FULL SCALE CURRENT */ + if (wled->fs_curr_ua > QPNP_WLED_FS_CURR_MAX_UA) + wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA; - rc = qpnp_wled_write_reg(wled, - QPNP_WLED_MOD_EN_REG(wled->sink_base, i), reg); - if (rc) - return rc; + rc = qpnp_wled_read_reg(wled, + QPNP_WLED_FS_CURR_REG(wled->sink_base, + wled->strings[i]), ®); + if (rc < 0) + return rc; + reg &= QPNP_WLED_FS_CURR_MASK; + if (wled->calc_curr) + temp = (wled->fs_curr_ua + (QPNP_WLED_FS_CURR_STEP_UA - 1)) / + QPNP_WLED_FS_CURR_STEP_UA; + else + temp = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA; + reg |= temp; + rc = qpnp_wled_write_reg(wled, + QPNP_WLED_FS_CURR_REG(wled->sink_base, + wled->strings[i]), reg); + if (rc) + return rc; - /* SINK EN */ - temp = wled->strings[i] + QPNP_WLED_CURR_SINK_SHIFT; - sink_en |= (1 << temp); - } - mask = QPNP_WLED_CURR_SINK_MASK; - rc = qpnp_wled_masked_write_reg(wled, - QPNP_WLED_CURR_SINK_REG(wled->sink_base), - mask, sink_en); - if (rc < 0) { - dev_err(&wled->pdev->dev, - "Failed to enable WLED sink config rc = %d\n", rc); - return rc; + /* CABC */ + rc = qpnp_wled_read_reg(wled, + QPNP_WLED_CABC_REG(wled->sink_base, + wled->strings[i]), ®); + if (rc < 0) + return rc; + reg &= QPNP_WLED_CABC_MASK; + reg |= (wled->en_cabc << QPNP_WLED_CABC_SHIFT); + rc = qpnp_wled_write_reg(wled, + QPNP_WLED_CABC_REG(wled->sink_base, + wled->strings[i]), reg); + if (rc) + return rc; + + /* Enable CURRENT SINK */ + rc = qpnp_wled_read_reg(wled, + QPNP_WLED_CURR_SINK_REG(wled->sink_base), ®); + if (rc < 0) + return rc; + temp = wled->strings[i] + QPNP_WLED_CURR_SINK_SHIFT; + reg |= (1 << temp); + rc = qpnp_wled_write_reg(wled, + QPNP_WLED_CURR_SINK_REG(wled->sink_base), reg); + if (rc) + return rc; + } } rc = qpnp_wled_sync_reg_toggle(wled); @@ -1952,13 +1910,8 @@ static int qpnp_wled_config(struct qpnp_wled *wled) wled->ovp_irq, rc); return rc; } - rc = qpnp_wled_read_reg(wled, - QPNP_WLED_MODULE_EN_REG(wled->ctrl_base), ®); - /* disable the OVP irq only if the module is not enabled */ - if (!rc && !(reg & QPNP_WLED_MODULE_EN_MASK)) { - disable_irq(wled->ovp_irq); - wled->ovp_irq_disabled = true; - } + disable_irq(wled->ovp_irq); + wled->ovp_irq_disabled = true; } if (wled->sc_irq >= 0) { @@ -2026,6 +1979,39 @@ static int qpnp_wled_config(struct qpnp_wled *wled) return 0; } +static void qpnp_wled_set_init_br(struct qpnp_wled *wled) +{ + int calc_init_br; + if (wled->fs_curr_ua) { + calc_init_br = (wled->cdev.max_brightness * wled->init_br_ua) + / wled->fs_curr_ua; + } else { + calc_init_br = (wled->cdev.max_brightness * wled->init_br_ua) + / QPNP_WLED_FS_CURR_MAX_UA; + } + qpnp_wled_set(&wled->cdev, calc_init_br); +} + +static int qpnp_wled_set_scale(struct qpnp_wled *wled) +{ + u8 reg = 0; + int rc, curr; + + wled->curr_scale = QPNP_WLED_CURR_SCALE_MAX; + rc = qpnp_wled_read_reg(wled, QPNP_WLED_FS_CURR_REG(wled->sink_base, + wled->strings[0]), ®); + if (rc) + return rc; + reg &= ~QPNP_WLED_FS_CURR_MASK; + curr = reg * QPNP_WLED_FS_CURR_STEP_UA; + if (curr > wled->fs_curr_ua) + wled->curr_scale = (wled->fs_curr_ua * + QPNP_WLED_CURR_SCALE_MAX) / curr; + dev_dbg(&wled->pdev->dev, "%s: curr = %d fs_curr_ua = %d curr_scale = %d\n", + __func__, curr, wled->fs_curr_ua, wled->curr_scale); + return 0; +} + /* parse wled dtsi parameters */ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) { @@ -2313,6 +2299,10 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) if (!rc) wled->cons_sync_write_delay_us = temp_val; + wled->calc_curr = of_property_read_bool(pdev->dev.of_node, + "somc,calc-curr"); + wled->bl_scale_enabled = of_property_read_bool(pdev->dev.of_node, + "somc,bl-scale-enabled"); wled->en_9b_dim_res = of_property_read_bool(pdev->dev.of_node, "qcom,en-9b-dim-res"); wled->en_phase_stag = of_property_read_bool(pdev->dev.of_node, @@ -2320,16 +2310,11 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) wled->en_cabc = of_property_read_bool(pdev->dev.of_node, "qcom,en-cabc"); - if (wled->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) - wled->max_strings = QPNP_PM660_WLED_MAX_STRINGS; - else - wled->max_strings = QPNP_WLED_MAX_STRINGS; - prop = of_find_property(pdev->dev.of_node, "qcom,led-strings-list", &temp_val); if (!prop || !temp_val || temp_val > QPNP_WLED_MAX_STRINGS) { dev_err(&pdev->dev, "Invalid strings info, use default"); - wled->num_strings = wled->max_strings; + wled->num_strings = QPNP_WLED_MAX_STRINGS; for (i = 0; i < wled->num_strings; i++) wled->strings[i] = i; } else { @@ -2353,8 +2338,50 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) wled->lcd_psm_ctrl = of_property_read_bool(pdev->dev.of_node, "qcom,lcd-psm-ctrl"); - wled->auto_calib_enabled = of_property_read_bool(pdev->dev.of_node, - "qcom,auto-calibration-enable"); + wled->init_br_ua = LED_OFF; + rc = of_property_read_u32(pdev->dev.of_node, + "somc,init-br-ua", &temp_val); + if (!rc) { + wled->init_br_ua = temp_val; + } else if (rc != -EINVAL) { + dev_err(&pdev->dev, "Unable to read init ua\n"); + return rc; + } + + rc = of_property_read_u32(pdev->dev.of_node, + "somc,area_count_table_size", &temp_val); + if (!rc) { + area_count_table_size = temp_val; + } else if (rc != -EINVAL) { + dev_err(&pdev->dev, "Unable to read area_count_table_size\n"); + return rc; + } + + if (area_count_table_size > 0) { + area_count_table = devm_kzalloc(&pdev->dev, + sizeof(int) * area_count_table_size, GFP_KERNEL); + if (!area_count_table) + return -ENOMEM; + + area_count = devm_kzalloc(&pdev->dev, + sizeof(unsigned long) * area_count_table_size, GFP_KERNEL); + if (!area_count_table) + return -ENOMEM; + + rc = of_property_read_u32_array(pdev->dev.of_node, "somc,area_count_table", + area_count_table, area_count_table_size); + if (rc < 0) { + dev_err(&pdev->dev, "Unable to read somc,area_count_table\n"); + temp_val = (WLED_MAX_LEVEL_4095 % (area_count_table_size - 1) > 0 ? + ((WLED_MAX_LEVEL_4095 / (area_count_table_size - 1)) + 1) : + (WLED_MAX_LEVEL_4095 / (area_count_table_size - 1))); + area_count_table[0] = 0; + for (i = 1; i < area_count_table_size; i++) { + area_count_table[i] = temp_val * i; + } + } + } + return 0; } @@ -2422,13 +2449,21 @@ static int qpnp_wled_probe(struct platform_device *pdev) } mutex_init(&wled->bus_lock); - mutex_init(&wled->lock); rc = qpnp_wled_config(wled); if (rc) { dev_err(&pdev->dev, "wled config failed\n"); return rc; } + if (wled->calc_curr) { + rc = qpnp_wled_set_scale(wled); + if (rc) { + dev_err(&pdev->dev, "wled config failed\n"); + return rc; + } + } + + mutex_init(&wled->lock); INIT_WORK(&wled->work, qpnp_wled_work); wled->ramp_ms = QPNP_WLED_RAMP_DLY_MS; wled->ramp_step = 1; @@ -2437,6 +2472,8 @@ static int qpnp_wled_probe(struct platform_device *pdev) wled->cdev.brightness_get = qpnp_wled_get; wled->cdev.max_brightness = WLED_MAX_LEVEL_4095; + now_area = 0; + start_jiffies = jiffies; rc = led_classdev_register(&pdev->dev, &wled->cdev); if (rc) { @@ -2453,6 +2490,9 @@ static int qpnp_wled_probe(struct platform_device *pdev) } } + if (wled->init_br_ua && !bl_on_in_boot) + qpnp_wled_set_init_br(wled); + return 0; sysfs_fail: @@ -2477,6 +2517,8 @@ static int qpnp_wled_remove(struct platform_device *pdev) led_classdev_unregister(&wled->cdev); cancel_work_sync(&wled->work); + devm_kfree(&pdev->dev, area_count_table); + devm_kfree(&pdev->dev, area_count); mutex_destroy(&wled->lock); return 0; diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c index e3cfffb5c563cebad18c9fe1c94f64ae3bf21495..c598ea1cc725558280c7f49bc7b851ade855bfd5 100644 --- a/drivers/leds/leds-qpnp.c +++ b/drivers/leds/leds-qpnp.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -175,7 +180,7 @@ #define RGB_LED_EN_CTL(base) (base + 0x46) #define RGB_LED_ATC_CTL(base) (base + 0x47) -#define RGB_MAX_LEVEL LED_FULL +#define RGB_MAX_LEVEL 512 #define RGB_LED_ENABLE_RED 0x80 #define RGB_LED_ENABLE_GREEN 0x40 #define RGB_LED_ENABLE_BLUE 0x20 @@ -251,6 +256,13 @@ #define NUM_KPDBL_LEDS 4 #define KPDBL_MASTER_BIT_INDEX 0 +#define RGB_LED_MAX_PAUSE_REG 254 +#define RGB_LED_MAX_PAUSE_TIME 130048 +#define RGB_LED_LUT_MAX_PAUSE 255 +#define RGB_LUT_INDEX_OFFSET 1 +#define RGB_CURR_DEFAULT_PATTERN 1 +#define RGB_CURR_UNIT_NUM 3 + /** * enum qpnp_leds - QPNP supported led ids * @QPNP_ID_WLED - White led backlight @@ -306,6 +318,8 @@ enum led_mode { PWM_MODE = 0, LPG_MODE, MANUAL_MODE, + PWM_DIRECT_MODE, + LPG_SYNC_MODE, }; static u8 wled_debug_regs[] = { @@ -353,6 +367,7 @@ static u8 gpio_debug_regs[] = { * @default_mode - default mode of LED as set in device tree * @use_blink - use blink sysfs entry * @blinking - device is currently blinking w/LPG mode + * @pwm_channel - pwm channel to be configured for led */ struct pwm_config_data { struct lut_params lut_params; @@ -365,6 +380,7 @@ struct pwm_config_data { bool pwm_enabled; bool use_blink; bool blinking; + int pwm_channel; }; /** @@ -499,10 +515,33 @@ struct kpdbl_config_data { * rgb_config_data - rgb configuration data * @pwm_cfg - device pwm configuration * @enable - bits to enable led + * @single_pwm_value - single color max value + * @mix_pwm_value - max color max value */ struct rgb_config_data { struct pwm_config_data *pwm_cfg; u8 enable; + u32 single_pwm_value; + u32 mix_pwm_value; +}; + +struct qpnp_led_data; +enum rgb_sync_state { + RGBSYNC_STATE_NOT_BLINK, + RGBSYNC_STATE_CONFIGURE_TO_BLINK, + RGBSYNC_STATE_BLINKING, +}; +#define LPG_CHANNEL_MAX 6 + +/** + * struct rgb_sync - rgb led synchrnize structure + * @config - pointer to rgb config data + */ +struct rgb_sync { + struct led_classdev cdev; + struct platform_device *pdev; + enum rgb_sync_state sync_state; + struct qpnp_led_data *led_data[LPG_CHANNEL_MAX]; }; /** @@ -552,6 +591,7 @@ struct qpnp_led_data { struct rgb_config_data *rgb_cfg; struct mpp_config_data *mpp_cfg; struct gpio_config_data *gpio_cfg; + struct rgb_sync *rgb_sync; int max_current; bool default_on; bool in_order_command_processing; @@ -564,6 +604,19 @@ static u32 kpdbl_master_period_us; DECLARE_BITMAP(kpdbl_leds_in_use, NUM_KPDBL_LEDS); static bool is_kpdbl_master_turn_on; +static int rgb_current_index; +static int __init rgb_current_setup(char *str) +{ + unsigned int res; + + if (!*str) + return 0; + if (!kstrtouint(str, 16, &res)) + rgb_current_index = res; + return 1; +} +__setup("oemandroidboot.babe137e=", rgb_current_setup); + static int qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val) { @@ -875,14 +928,6 @@ static int qpnp_mpp_set(struct qpnp_led_data *led) } if (led->mpp_cfg->pwm_mode == PWM_MODE) { /*config pwm for brightness scaling*/ - rc = pwm_change_mode(led->mpp_cfg->pwm_cfg->pwm_dev, - PM_PWM_MODE_PWM); - if (rc < 0) { - dev_err(&led->pdev->dev, - "Failed to set PWM mode, rc = %d\n", - rc); - return rc; - } period_us = led->mpp_cfg->pwm_cfg->pwm_period_us; if (period_us > INT_MAX / NSEC_PER_USEC) { duty_us = (period_us * led->cdev.brightness) / @@ -1589,14 +1634,6 @@ static int qpnp_kpdbl_set(struct qpnp_led_data *led) } if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) { - rc = pwm_change_mode(led->kpdbl_cfg->pwm_cfg->pwm_dev, - PM_PWM_MODE_PWM); - if (rc < 0) { - dev_err(&led->pdev->dev, - "Failed to set PWM mode, rc = %d\n", - rc); - return rc; - } period_us = led->kpdbl_cfg->pwm_cfg->pwm_period_us; if (period_us > INT_MAX / NSEC_PER_USEC) { duty_us = (period_us * led->cdev.brightness) / @@ -1708,27 +1745,103 @@ static int qpnp_kpdbl_set(struct qpnp_led_data *led) return 0; } +#ifdef CONFIG_LEDS_QPNP_RGB_SCALE +static int rgb_scale = 100; + +static int scale_brightness(const struct qpnp_led_data *led) +{ + int brightness = led->cdev.brightness; + + if (rgb_scale != 100) { + brightness = (brightness*rgb_scale + 50) / 100; + brightness = clamp(brightness, + 1, (int)led->cdev.max_brightness); + } + + return brightness; +} +#else +static int scale_brightness(const struct qpnp_led_data *led) +{ + return led->cdev.brightness; +} +#endif + +static int qpnp_rgb_set_direct(struct qpnp_led_data *led) +{ + struct pwm_period_config pwm_config = { + .pwm_size = PM_PWM_SIZE_9BIT, + .clk = PM_PWM_CLK_19P2MHZ, + .pre_div = PM_PWM_PDIV_5, + .pre_div_exp = 3, + }; + int rc; + + if (led->rgb_cfg->pwm_cfg->mode == LPG_SYNC_MODE) { + dev_err(&led->pdev->dev, "%s wrong mode\n", __func__); + return -EFAULT; + } + + if (led->cdev.brightness) { + int brightness = scale_brightness(led); + + rc = pwm_config_period_value(led->rgb_cfg->pwm_cfg->pwm_dev, + &pwm_config, brightness); + if (rc < 0) { + dev_err(&led->pdev->dev, + "pwm config failed\n"); + return rc; + } + rc = qpnp_led_masked_write(led, + RGB_LED_EN_CTL(led->base), + led->rgb_cfg->enable, led->rgb_cfg->enable); + if (rc) { + dev_err(&led->pdev->dev, + "Failed to write led enable reg\n"); + return rc; + } + if (led->rgb_cfg->pwm_cfg->pwm_enabled) { + pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev); + led->rgb_cfg->pwm_cfg->pwm_enabled = 0; + } + rc = pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev); + if (!rc) + led->rgb_cfg->pwm_cfg->pwm_enabled = 1; + } else { + pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev); + led->rgb_cfg->pwm_cfg->pwm_enabled = 0; + rc = qpnp_led_masked_write(led, + RGB_LED_EN_CTL(led->base), + led->rgb_cfg->enable, RGB_LED_DISABLE); + if (rc) { + dev_err(&led->pdev->dev, + "Failed to write led enable reg\n"); + return rc; + } + } + + return 0; +} + static int qpnp_rgb_set(struct qpnp_led_data *led) { int rc; int duty_us, duty_ns, period_us; + if ((led->rgb_cfg->pwm_cfg->mode == PWM_DIRECT_MODE) + || (led->rgb_cfg->pwm_cfg->mode == LPG_SYNC_MODE)) + return qpnp_rgb_set_direct(led); + if (led->cdev.brightness) { + int brightness = scale_brightness(led); + if (!led->rgb_cfg->pwm_cfg->blinking) led->rgb_cfg->pwm_cfg->mode = led->rgb_cfg->pwm_cfg->default_mode; if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) { - rc = pwm_change_mode(led->rgb_cfg->pwm_cfg->pwm_dev, - PM_PWM_MODE_PWM); - if (rc < 0) { - dev_err(&led->pdev->dev, - "Failed to set PWM mode, rc = %d\n", - rc); - return rc; - } period_us = led->rgb_cfg->pwm_cfg->pwm_period_us; if (period_us > INT_MAX / NSEC_PER_USEC) { - duty_us = (period_us * led->cdev.brightness) / + duty_us = (period_us * brightness) / LED_FULL; rc = pwm_config_us( led->rgb_cfg->pwm_cfg->pwm_dev, @@ -1736,7 +1849,7 @@ static int qpnp_rgb_set(struct qpnp_led_data *led) period_us); } else { duty_ns = ((period_us * NSEC_PER_USEC) / - LED_FULL) * led->cdev.brightness; + LED_FULL) * brightness; rc = pwm_config( led->rgb_cfg->pwm_cfg->pwm_dev, duty_ns, @@ -1887,7 +2000,7 @@ static int qpnp_led_set_max_brightness(struct qpnp_led_data *led) case QPNP_ID_RGB_RED: case QPNP_ID_RGB_GREEN: case QPNP_ID_RGB_BLUE: - led->cdev.max_brightness = RGB_MAX_LEVEL; + led->cdev.max_brightness = led->max_current; break; case QPNP_ID_LED_MPP: if (led->mpp_cfg->pwm_mode == MANUAL_MODE) @@ -2160,11 +2273,6 @@ static int qpnp_pwm_init(struct pwm_config_data *pwm_cfg, dev_err(&pdev->dev, "Failed to configure pwm LUT\n"); return rc; } - rc = pwm_change_mode(pwm_cfg->pwm_dev, PM_PWM_MODE_LPG); - if (rc < 0) { - dev_err(&pdev->dev, "Failed to set LPG mode\n"); - return rc; - } } } else { dev_err(&pdev->dev, "Invalid PWM device\n"); @@ -2958,9 +3066,456 @@ static int qpnp_kpdbl_init(struct qpnp_led_data *led) return 0; } + +static void qpnp_rgb_set_duration(struct qpnp_led_data *led) +{ + unsigned long long_pause, duration; + const unsigned max_pause = RGB_LED_MAX_PAUSE_REG; + const unsigned max_pause_time = RGB_LED_MAX_PAUSE_TIME; + + if (led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi > max_pause_time) + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi + = max_pause_time; + if (led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo > max_pause_time) + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo + = max_pause_time; + + long_pause = ((led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi + >= led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo) ? + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi : + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo); + duration = (long_pause + (max_pause - 1)) / max_pause; + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi + = (led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi / duration) + 1; + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo + = (led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo / duration) + 1; + led->rgb_cfg->pwm_cfg->lut_params.ramp_step_ms = (duration - 1); + led->rgb_cfg->pwm_cfg->lut_params.use_duration = false; + + pr_debug("%s : pause_hi=%d pause_lo=%d step_ms=%d\n", __func__, + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi, + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo, + led->rgb_cfg->pwm_cfg->lut_params.ramp_step_ms); + + return; +} + +static int rgbled_set_lut_to_register(struct qpnp_led_data *led) +{ + int rc; + int i; + + /* set PWM period to 1.06666[ms] (2^9 {9bit} * 5 * 2^3 / 19.2 [us]) */ + struct pwm_period_config pwm_config = { + .pwm_size = PM_PWM_SIZE_9BIT, + .clk = PM_PWM_CLK_19P2MHZ, + .pre_div = PM_PWM_PDIV_5, + .pre_div_exp = 3, + }; + struct lut_config lut_conf = { + .hi_index = led->rgb_cfg->pwm_cfg->duty_cycles->start_idx + + led->rgb_cfg->pwm_cfg->lut_params.idx_len - 1, + .lo_index = led->rgb_cfg->pwm_cfg->duty_cycles->start_idx, + .lut_pause_hi = led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi, + .lut_pause_lo = led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo, + .ramp_step_ms = led->rgb_cfg->pwm_cfg->lut_params.ramp_step_ms, + .flags = PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP + | PM_PWM_LUT_PAUSE_HI_EN + | PM_PWM_LUT_PAUSE_LO_EN | PM_PWM_LUT_USE_RAW_VALUE, + }; + int *lut = led->rgb_cfg->pwm_cfg->duty_cycles->duty_pcts; + + /* set LPG offset 0x41,0x42 */ + rc = pwm_config_period(led->rgb_cfg->pwm_cfg->pwm_dev, &pwm_config); + for (i = 0; i < INDEX_MAX_EACH_LED; ++i) + lut_conf.lut[i] = lut[i]; + /* set LPG offset 0x40,0x46,0x50-0x57 and LUT */ + rc = pwm_config_lut(led->rgb_cfg->pwm_cfg->pwm_dev, &lut_conf); + + return rc; +} + +static ssize_t rgbled_lut_pwm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_led_data *led; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + int *lut; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + lut = led->rgb_cfg->pwm_cfg->duty_cycles->duty_pcts; + + ret = sscanf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + lut, lut+1, lut+2, lut+3, lut+4, lut+5, lut+6, lut+7, + lut+8, lut+9, lut+10, lut+11, lut+12, lut+13, lut+14, lut+15); + if (ret == 0) { + lut[0] = 0; + ret = 1; + } + + led->rgb_cfg->pwm_cfg->duty_cycles->start_idx + = led->rgb_cfg->pwm_cfg->lut_params.start_idx + = (led->rgb_cfg->pwm_cfg->pwm_channel * INDEX_MAX_EACH_LED) + + RGB_LUT_INDEX_OFFSET; + led->rgb_cfg->pwm_cfg->lut_params.idx_len = ret; + + return count; +} + +static ssize_t rgbled_lut_pwm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_data *led; + int *lut; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + lut = led->rgb_cfg->pwm_cfg->duty_cycles->duty_pcts; + + return scnprintf(buf, PAGE_SIZE, "len:%u,[0]:%d,[1]:%d\n", + led->rgb_cfg->pwm_cfg->lut_params.idx_len, lut[0], lut[1]); +} + +static ssize_t rgbled_step_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_led_data *led; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + unsigned long duration; + const unsigned ramp_step_duration_max = 511; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + + ret = kstrtoul(buf, 10, &duration); + if (ret) + return ret; + + if (duration > ramp_step_duration_max) + duration = ramp_step_duration_max; + led->rgb_cfg->pwm_cfg->lut_params.ramp_step_ms = duration; + + return count; +} + +static ssize_t rgbled_step_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_data *led; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + led->rgb_cfg->pwm_cfg->lut_params.ramp_step_ms); +} + +static ssize_t rgbled_pause_hi_multi_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_led_data *led; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + unsigned long lut_pause; + const unsigned lut_pause_max = RGB_LED_LUT_MAX_PAUSE; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + + ret = kstrtoul(buf, 10, &lut_pause); + if (ret) + return ret; + + if (lut_pause > lut_pause_max) + led->rgb_cfg->pwm_cfg->lut_params.use_duration = true; + + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi = lut_pause; + + return count; +} + +static ssize_t rgbled_pause_hi_multi_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_data *led; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_hi); +} + +static ssize_t rgbled_pause_lo_multi_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_led_data *led; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + unsigned long lut_pause; + const unsigned lut_pause_max = RGB_LED_LUT_MAX_PAUSE; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + + ret = kstrtoul(buf, 10, &lut_pause); + if (ret) + return ret; + + if (lut_pause > lut_pause_max) + led->rgb_cfg->pwm_cfg->lut_params.use_duration = true; + + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo = lut_pause; + return count; +} + +static ssize_t rgbled_pause_lo_multi_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_data *led; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + led->rgb_cfg->pwm_cfg->lut_params.lut_pause_lo); +} + +static ssize_t rgbled_single_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_data *led; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + led->rgb_cfg->single_pwm_value); +} + +static ssize_t rgbled_mix_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_data *led; + + led = container_of(led_cdev, struct qpnp_led_data, cdev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + led->rgb_cfg->mix_pwm_value); +} + +static struct device_attribute rgbled_attrs[] = { + __ATTR(lut_pwm, S_IRUGO | S_IWUSR | S_IWGRP, + rgbled_lut_pwm_show, rgbled_lut_pwm_store), + __ATTR(step_duration, S_IRUGO | S_IWUSR | S_IWGRP, + rgbled_step_duration_show, rgbled_step_duration_store), + __ATTR(pause_hi_multi, S_IRUGO | S_IWUSR | S_IWGRP, + rgbled_pause_hi_multi_show, rgbled_pause_hi_multi_store), + __ATTR(pause_lo_multi, S_IRUGO | S_IWUSR | S_IWGRP, + rgbled_pause_lo_multi_show, rgbled_pause_lo_multi_store), + __ATTR(max_single_brightness, S_IRUGO, + rgbled_single_value_show, NULL), + __ATTR(max_mix_brightness, S_IRUGO, + rgbled_mix_value_show, NULL), + __ATTR_NULL, +}; + +static int rgbcommon_turn_off_force(struct rgb_sync *rgb_sync) +{ + int i; + int rc = 0; + for (i = 0; i < LPG_CHANNEL_MAX; ++i) + if (rgb_sync->led_data[i]) { + struct qpnp_led_data *led = rgb_sync->led_data[i]; + led->cdev.brightness = 0; + led->rgb_cfg->pwm_cfg->lut_params.idx_len = 0; + rc = qpnp_led_masked_write(led, + RGB_LED_EN_CTL(led->base), + led->rgb_cfg->enable, RGB_LED_DISABLE); + if (rc) + break; + } + + return rc; +} + +static ssize_t rgbcommon_sync_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rgb_sync *rgb_sync; + unsigned long state; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + int i; + int rc; + enum led_mode led_mode; + enum pm_pwm_mode pwm_mode; + + ret = kstrtoul(buf, 10, &state); + if (ret) + return ret; + if (state > RGBSYNC_STATE_BLINKING) { + dev_err(dev, "%s out of range\n", __func__); + return -EFAULT; + } + rgb_sync = container_of(led_cdev, struct rgb_sync, cdev); + if (!rgb_sync) { + dev_err(dev, "%s rgb_sync NULL\n", __func__); + return -EFAULT; + } + + if (rgb_sync->sync_state == state) { + dev_err(dev, "%s do nothing. same state", __func__); + return count; + } else if ((rgb_sync->sync_state == RGBSYNC_STATE_BLINKING) + || ((rgb_sync->sync_state == RGBSYNC_STATE_NOT_BLINK) + && (state == RGBSYNC_STATE_CONFIGURE_TO_BLINK))) { + dev_err(dev, "%s turn off force. state changed\n", __func__); + rc = rgbcommon_turn_off_force(rgb_sync); + if (rc) + dev_err(dev, "Failed to turn off force\n"); + } + switch (rgb_sync->sync_state = state) { + case RGBSYNC_STATE_NOT_BLINK: + led_mode = PWM_DIRECT_MODE; + pwm_mode = PM_PWM_MODE_PWM; + break; + case RGBSYNC_STATE_CONFIGURE_TO_BLINK: + led_mode = LPG_SYNC_MODE; + pwm_mode = PM_PWM_MODE_LPG; + break; + default: + return count; + break; + } + + for (i = 0; i < LPG_CHANNEL_MAX; ++i) + if (rgb_sync->led_data[i]) { + struct qpnp_led_data *led = rgb_sync->led_data[i]; + led->rgb_cfg->pwm_cfg->mode = led_mode; + rc = pwm_change_mode(led->rgb_cfg->pwm_cfg->pwm_dev, + pwm_mode); + if (rc) + break; + } + + return count; +} + +static ssize_t rgbcommon_sync_state_show(struct device *ldev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(ldev); + struct device *dev = led_cdev->dev->parent; + struct rgb_sync *rgb_sync; + + rgb_sync = container_of(led_cdev, struct rgb_sync, cdev); + if (!rgb_sync) { + dev_err(dev, "%s rgb_sync NULL\n", __func__); + return -EFAULT; + } + return scnprintf(buf, PAGE_SIZE, "%u\n", rgb_sync->sync_state); +} + +static ssize_t rgbcommon_start_blink_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rgb_sync *rgb_sync; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + int i; + struct qpnp_led_data *led = NULL; + int rc; + int ramp_control = 0; + + rgb_sync = container_of(led_cdev, struct rgb_sync, cdev); + if (!rgb_sync) { + dev_err(dev, "%s rgb_sync NULL\n", __func__); + return -EFAULT; + } + + if (rgb_sync->sync_state != RGBSYNC_STATE_CONFIGURE_TO_BLINK) { + dev_err(dev, "%s ignore. not configure to blink state\n", + __func__); + return count; + } + + rgb_sync->sync_state = RGBSYNC_STATE_BLINKING; + /* must set only led which is blinked */ + for (i = 0; i < LPG_CHANNEL_MAX; ++i) { + if (!rgb_sync->led_data[i]) + continue; + led = rgb_sync->led_data[i]; + if (led->rgb_cfg->pwm_cfg->lut_params.use_duration) + qpnp_rgb_set_duration(led); + if (led->rgb_cfg->pwm_cfg->lut_params.idx_len) { + rgbled_set_lut_to_register(led); + ramp_control |= (1 << i); + rc = qpnp_led_masked_write(led, + RGB_LED_EN_CTL(led->base), + led->rgb_cfg->enable, led->rgb_cfg->enable); + } + } + + if (led) { + rc = pwm_start_lut_ramp(led->rgb_cfg->pwm_cfg->pwm_dev, + ramp_control); + if (rc) + dev_err(dev, "Failed to start blink\n"); + } else { + dev_err(dev, "try to start blink. however not configured.\n"); + } + + return count; +} + +static struct device_attribute rgbcommon_attr[] = { + __ATTR(sync_state, S_IRUGO | S_IWUSR | S_IWGRP, + rgbcommon_sync_state_show, rgbcommon_sync_state_store), + __ATTR(start_blink, S_IWUSR | S_IWGRP, + NULL, rgbcommon_start_blink_store), + __ATTR_NULL, +}; + +static void qpnp_remove_attributes(struct device *dev, + struct device_attribute *attrs) +{ + int i; + + for (i = 0; attrs[i].attr.name; i++) + device_remove_file(dev, &attrs[i]); +} + +static int qpnp_add_attributes(struct device *dev, + struct device_attribute *attrs) +{ + int error = 0; + int i; + + for (i = 0; attrs[i].attr.name; i++) { + error = device_create_file(dev, &attrs[i]); + if (error) { + dev_err(dev, "%s: failed.\n", __func__); + goto err; + } + } + return 0; +err: + while (--i >= 0) + device_remove_file(dev, &attrs[i]); + return error; +} + + static int qpnp_rgb_init(struct qpnp_led_data *led) { int rc; + int max_pwm_value; rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base), RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR); @@ -2975,6 +3530,24 @@ static int qpnp_rgb_init(struct qpnp_led_data *led) dev_err(&led->pdev->dev, "Failed to initialize pwm\n"); return rc; } + + if (led->rgb_sync) { + led->rgb_sync->led_data[led->rgb_cfg->pwm_cfg->pwm_channel] + = led; + led->rgb_cfg->pwm_cfg->mode = PWM_DIRECT_MODE; + rc = pwm_change_mode(led->rgb_cfg->pwm_cfg->pwm_dev, + PM_PWM_MODE_PWM); + if (rc < 0) { + dev_err(&led->pdev->dev, "Failed to " \ + "configure pwm mode\n"); + return rc; + } + } + pwm_set_max_pwm_value(led->rgb_cfg->pwm_cfg->pwm_dev, led->max_current); + max_pwm_value = pwm_get_max_pwm_value(led->rgb_cfg->pwm_cfg->pwm_dev); + led->max_current + = max_pwm_value ? max_pwm_value : RGB_MAX_LEVEL; + /* Initialize led for use in auto trickle charging mode */ rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base), led->rgb_cfg->enable, led->rgb_cfg->enable); @@ -3645,7 +4218,9 @@ static int qpnp_get_config_kpdbl(struct qpnp_led_data *led, static int qpnp_get_config_rgb(struct qpnp_led_data *led, struct device_node *node) { - int rc; + int rc, current_index, i; + u32 val, color_variation_max_num; + u32 *rgb_current_table; u8 led_mode; const char *mode; @@ -3684,6 +4259,82 @@ static int qpnp_get_config_rgb(struct qpnp_led_data *led, return rc; } + rc = of_property_read_u32(node, + "somc,color_variation_max_num", + &color_variation_max_num); + if (rc < 0) { + dev_err(&led->pdev->dev, "Unable to read color_variation_max_num\n"); + color_variation_max_num = RGB_CURR_DEFAULT_PATTERN; + } + dev_info(&led->pdev->dev, "color_variation_max_num[%d] rgb_current_index[%d]\n", + color_variation_max_num, rgb_current_index); + + rgb_current_table = devm_kzalloc(&led->pdev->dev, + sizeof(u32) * color_variation_max_num * RGB_CURR_UNIT_NUM, + GFP_KERNEL); + if (rgb_current_table) { + rc = of_property_read_u32_array(node, "somc,max_current", + rgb_current_table, + color_variation_max_num * RGB_CURR_UNIT_NUM); + if (rc < 0) { + dev_err(&led->pdev->dev, "Unable to read max_mix_current\n"); + led->rgb_cfg->single_pwm_value = RGB_MAX_LEVEL - 1; + led->rgb_cfg->mix_pwm_value = RGB_MAX_LEVEL - 1; + } else { + for (i = 0; i < color_variation_max_num; i++) { + current_index = i * RGB_CURR_UNIT_NUM; + if (rgb_current_index == rgb_current_table[current_index]) { + break; + } + } + led->rgb_cfg->single_pwm_value = + rgb_current_table[current_index + 1]; + led->rgb_cfg->mix_pwm_value = + rgb_current_table[current_index + 2]; + } + } else { + dev_err(&led->pdev->dev, "Unable to allocate memory\n"); + led->rgb_cfg->single_pwm_value = RGB_MAX_LEVEL - 1; + led->rgb_cfg->mix_pwm_value = RGB_MAX_LEVEL - 1; + } + devm_kfree(&led->pdev->dev, rgb_current_table); + + led->max_current = (led->rgb_cfg->single_pwm_value > + led->rgb_cfg->mix_pwm_value ? + led->rgb_cfg->single_pwm_value : + led->rgb_cfg->mix_pwm_value); + dev_info(&led->pdev->dev, "single_pwm_value[%d] mix_pwm_value[%d]\n", + led->rgb_cfg->single_pwm_value, led->rgb_cfg->mix_pwm_value); + dev_info(&led->pdev->dev, "max_current[%d]\n", led->max_current); + + if (led->rgb_sync) { + rc = of_property_read_u32(node, "somc,pwm-channel", &val); + if (!rc) + led->rgb_cfg->pwm_cfg->pwm_channel = val; + else + return rc; + + /* allocate memory for simple use case */ + led->rgb_cfg->pwm_cfg->duty_cycles = + devm_kzalloc(&led->pdev->dev, + sizeof(struct pwm_duty_cycles), GFP_KERNEL); + if (!led->rgb_cfg->pwm_cfg->duty_cycles) { + dev_err(&led->pdev->dev, + "Unable to allocate memory\n"); + return -ENOMEM; + } + led->rgb_cfg->pwm_cfg->duty_cycles->duty_pcts = + devm_kzalloc(&led->pdev->dev, + sizeof(int) * INDEX_MAX_EACH_LED, GFP_KERNEL); + if (!led->rgb_cfg->pwm_cfg->duty_cycles->duty_pcts) { + dev_err(&led->pdev->dev, + "Unable to allocate memory\n"); + return -ENOMEM; + } + led->rgb_cfg->pwm_cfg->pwm_dev = of_pwm_get(node, NULL); + return 0; + } + rc = qpnp_get_config_pwm(led->rgb_cfg->pwm_cfg, led->pdev, node); if (rc < 0) { if (led->rgb_cfg->pwm_cfg->pwm_dev) @@ -3872,6 +4523,8 @@ static int qpnp_leds_probe(struct platform_device *pdev) int rc, i, num_leds = 0, parsed_leds = 0; const char *led_label; bool regulator_probe = false; + int prepare_rgb_sync; + struct rgb_sync *rgb_sync = NULL; node = pdev->dev.of_node; if (node == NULL) @@ -3889,10 +4542,34 @@ static int qpnp_leds_probe(struct platform_device *pdev) if (!led_array) return -ENOMEM; + rc = of_property_read_u32(node, "qcom,rgb_sync", &prepare_rgb_sync); + if (rc < 0) + prepare_rgb_sync = 0; + if (prepare_rgb_sync) + rgb_sync = devm_kzalloc(&pdev->dev, + sizeof(struct rgb_sync), GFP_KERNEL); + if (rgb_sync) { + rgb_sync->cdev.name = "rgb"; + rgb_sync->pdev = pdev; + rc = led_classdev_register(&pdev->dev, &rgb_sync->cdev); + if (rc) { + dev_err(&pdev->dev, "unable to register rgb %d\n", rc); + rgb_sync = 0; + } + rc = rc ? rc : + qpnp_add_attributes(rgb_sync->cdev.dev, rgbcommon_attr); + if (rc) { + dev_err(&pdev->dev, "unable to create sysfs %d\n", rc); + rgb_sync = 0; + } + } + dev_info(&pdev->dev, "rgb_sync prepare %d\n", prepare_rgb_sync); + for_each_child_of_node(node, temp) { led = &led_array[parsed_leds]; led->num_leds = num_leds; led->regmap = dev_get_regmap(pdev->dev.parent, NULL); + led->rgb_sync = rgb_sync; if (!led->regmap) { dev_err(&pdev->dev, "Couldn't get parent's regmap\n"); return -EINVAL; @@ -4048,6 +4725,14 @@ static int qpnp_leds_probe(struct platform_device *pdev) } + if (led->id == QPNP_ID_RGB_RED || + led->id == QPNP_ID_RGB_GREEN || + led->id == QPNP_ID_RGB_BLUE) { + rc = qpnp_add_attributes(led->cdev.dev, rgbled_attrs); + if (rc) + goto fail_id_check; + } + if (led->id == QPNP_ID_LED_MPP) { if (!led->mpp_cfg->pwm_cfg) break; @@ -4182,6 +4867,8 @@ static int qpnp_leds_remove(struct platform_device *pdev) case QPNP_ID_RGB_RED: case QPNP_ID_RGB_GREEN: case QPNP_ID_RGB_BLUE: + qpnp_remove_attributes(led_array[i].cdev.dev, + rgbled_attrs); if (led_array[i].rgb_cfg->pwm_cfg->mode == PWM_MODE) sysfs_remove_group(&led_array[i].cdev.dev->kobj, &pwm_attr_group); @@ -4256,6 +4943,52 @@ static struct platform_driver qpnp_leds_driver = { .remove = qpnp_leds_remove, }; +#ifdef CONFIG_LEDS_QPNP_RGB_SCALE +static int update_rgb_brightness(struct device *dev, void *arg) +{ + struct qpnp_led_data *led = dev_get_drvdata(dev); + int i; + + for (i = 0; i < led->num_leds; i++) { + if (led[i].id != QPNP_ID_RGB_RED && + led[i].id != QPNP_ID_RGB_GREEN && + led[i].id != QPNP_ID_RGB_BLUE) { + continue; + } + + dev_info(led[i].cdev.dev, "brightness scale %d%%\n", rgb_scale); + + qpnp_led_set(&led[i].cdev, led[i].cdev.brightness); + } + + return 0; +} + +int qpnp_led_set_rgb_scale(int scale) +{ + int ret = 0; + static DEFINE_MUTEX(scale_lock); + + if (!qpnp_leds_driver.driver.bus) + return -ENODEV; + + if (scale < 1 || scale > 100) + return -EINVAL; + + mutex_lock(&scale_lock); + + if (scale != rgb_scale) { + rgb_scale = scale; + ret = driver_for_each_device(&qpnp_leds_driver.driver, + NULL, NULL, update_rgb_brightness); + } + + mutex_unlock(&scale_lock); + + return ret; +} +#endif + static int __init qpnp_led_init(void) { return platform_driver_register(&qpnp_leds_driver); diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c index b88900d721e4494e9e05c494e7d9977501cda97b..f05a9889de84c9be9dc41cae02d5bbc507bf5f58 100644 --- a/drivers/leds/leds-syscon.c +++ b/drivers/leds/leds-syscon.c @@ -19,6 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 27713412c8811330b5f0df2fbf210e04ab9e57a5..b2f290858b40a86c40f35637ee7762406bc98d2f 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -562,4 +562,11 @@ config DM_ANDROID_VERITY of the metadata contents are verified against the key included in the system keyring. Upon success, the underlying verity target is setup. + +config PANIC_ON_DM_VERITY_ERRORS + bool "panic on dm verity errors" + depends on DM_VERITY = y + default n + ---help--- + This enables panic on hash mismatch dm-verity errors. endif # MD diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c index 43d566fd38ae436a2b7e9191d014e3ed9a2d9b23..4f6086970131104398a9aa5a44321938d9e3fffb 100644 --- a/drivers/md/dm-android-verity.c +++ b/drivers/md/dm-android-verity.c @@ -645,8 +645,6 @@ static int add_as_linear_device(struct dm_target *ti, char *dev) android_verity_target.iterate_devices = dm_linear_iterate_devices, android_verity_target.io_hints = NULL; - set_disk_ro(dm_disk(dm_table_get_md(ti->table)), 0); - err = dm_linear_ctr(ti, DM_LINEAR_ARGS, linear_table_args); if (!err) { diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index e34cf53bd0686f3f581f7942f7fd68561c675fab..4635e5b8040bebb28deff9a28427d7962f724cf4 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -13,6 +13,11 @@ * are on the same disk on different partitions on devices with poor random * access behavior. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "dm-verity.h" #include "dm-verity-fec.h" @@ -20,6 +25,10 @@ #include #include +#ifdef CONFIG_RAMDUMP_TAGS +#include +#endif + #define DM_MSG_PREFIX "verity" #define DM_VERITY_ENV_LENGTH 42 @@ -39,6 +48,11 @@ static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE; module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR); +#ifdef CONFIG_PANIC_ON_DM_VERITY_ERRORS +static unsigned dm_verity_panic_on_err; +module_param_named(panic_on_err, dm_verity_panic_on_err, uint, S_IRUGO | S_IWUSR); +#endif + struct dm_verity_prefetch_work { struct work_struct work; struct dm_verity *v; @@ -188,6 +202,16 @@ static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level, *offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits); } +static void add_verity_block_tag(unsigned long long blk) +{ + char verity_blk[64]; + int count = 0; + + count = snprintf(verity_blk, sizeof(verity_blk), "0x%llx", blk); + + rdtags_add_tag("rdtag_verity_block_nr", verity_blk, count); +} + /* * Handle verification errors. */ @@ -221,6 +245,16 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type, DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str, block); +#ifdef CONFIG_PANIC_ON_DM_VERITY_ERRORS + if (dm_verity_panic_on_err) { +#ifdef CONFIG_RAMDUMP_TAGS + add_verity_block_tag(block); +#endif + panic("%s: %s block %llu is corrupted", + v->data_dev->name, type_str, block); + } +#endif + if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS) DMERR("%s: reached maximum errors", v->data_dev->name); diff --git a/drivers/md/md.c b/drivers/md/md.c index 0a856cb181e918736731e9ae89f3580763b5ca29..eff554a12fb428560310da77b7b08457d9d57e7b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1866,7 +1866,7 @@ super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors) } sb = page_address(rdev->sb_page); sb->data_size = cpu_to_le64(num_sectors); - sb->super_offset = cpu_to_le64(rdev->sb_start); + sb->super_offset = rdev->sb_start; sb->sb_csum = calc_sb_1_csum(sb); md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size, rdev->sb_page); @@ -2273,7 +2273,7 @@ static bool does_sb_need_changing(struct mddev *mddev) /* Check if any mddev parameters have changed */ if ((mddev->dev_sectors != le64_to_cpu(sb->size)) || (mddev->reshape_position != le64_to_cpu(sb->reshape_position)) || - (mddev->layout != le32_to_cpu(sb->layout)) || + (mddev->layout != le64_to_cpu(sb->layout)) || (mddev->raid_disks != le32_to_cpu(sb->raid_disks)) || (mddev->chunk_sectors != le32_to_cpu(sb->chunksize))) return true; diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index bc957528f69ffbac8310b051e9f50c67ba181b51..8ef6399d794f82cb8ac9cb9df049da89f750e18f 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -355,43 +355,12 @@ static struct i2c_client saa7134_client_template = { /* ----------------------------------------------------------- */ -/* On Medion 7134 reading EEPROM needs DVB-T demod i2c gate open */ -static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev) -{ - u8 subaddr = 0x7, dmdregval; - u8 data[2]; - int ret; - struct i2c_msg i2cgatemsg_r[] = { {.addr = 0x08, .flags = 0, - .buf = &subaddr, .len = 1}, - {.addr = 0x08, - .flags = I2C_M_RD, - .buf = &dmdregval, .len = 1} - }; - struct i2c_msg i2cgatemsg_w[] = { {.addr = 0x08, .flags = 0, - .buf = data, .len = 2} }; - - ret = i2c_transfer(&dev->i2c_adap, i2cgatemsg_r, 2); - if ((ret == 2) && (dmdregval & 0x2)) { - pr_debug("%s: DVB-T demod i2c gate was left closed\n", - dev->name); - - data[0] = subaddr; - data[1] = (dmdregval & ~0x2); - if (i2c_transfer(&dev->i2c_adap, i2cgatemsg_w, 1) != 1) - pr_err("%s: EEPROM i2c gate open failure\n", - dev->name); - } -} - static int saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len) { unsigned char buf; int i,err; - if (dev->board == SAA7134_BOARD_MD7134) - saa7134_i2c_eeprom_md7134_gate(dev); - dev->i2c_client.addr = 0xa0 >> 1; buf = 0; if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) { diff --git a/drivers/media/platform/msm/ais/camera/camera.c b/drivers/media/platform/msm/ais/camera/camera.c index 3f477d50ceafa7ac7ecaf74d282631621e25094f..33808d18d4c4c199721bcb91ac851cabe5db8f20 100644 --- a/drivers/media/platform/msm/ais/camera/camera.c +++ b/drivers/media/platform/msm/ais/camera/camera.c @@ -628,7 +628,6 @@ static int camera_v4l2_open(struct file *filep) if (WARN_ON(!pvdev)) return -EIO; - mutex_lock(&pvdev->video_drvdata_mutex); rc = camera_v4l2_fh_open(filep); if (rc < 0) { pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n", @@ -699,7 +698,6 @@ static int camera_v4l2_open(struct file *filep) idx |= (1 << find_first_zero_bit((const unsigned long *)&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); atomic_cmpxchg(&pvdev->opened, opn_idx, idx); - mutex_unlock(&pvdev->video_drvdata_mutex); return rc; @@ -714,7 +712,6 @@ stream_fail: vb2_q_fail: camera_v4l2_fh_release(filep); fh_open_fail: - mutex_unlock(&pvdev->video_drvdata_mutex); return rc; } @@ -749,7 +746,6 @@ static int camera_v4l2_close(struct file *filep) if (WARN_ON(!session)) return -EIO; - mutex_lock(&pvdev->video_drvdata_mutex); mutex_lock(&session->close_lock); opn_idx = atomic_read(&pvdev->opened); mask = (1 << sp->stream_id); @@ -792,7 +788,6 @@ static int camera_v4l2_close(struct file *filep) } camera_v4l2_fh_release(filep); - mutex_unlock(&pvdev->video_drvdata_mutex); return 0; } @@ -941,7 +936,6 @@ int camera_init_v4l2(struct device *dev, unsigned int *session) *session = pvdev->vdev->num; atomic_set(&pvdev->opened, 0); - mutex_init(&pvdev->video_drvdata_mutex); video_set_drvdata(pvdev->vdev, pvdev); device_init_wakeup(&pvdev->vdev->dev, 1); goto init_end; diff --git a/drivers/media/platform/msm/ais/fd/msm_fd_dev.c b/drivers/media/platform/msm/ais/fd/msm_fd_dev.c index d9e109938e7e9d6f4dfe6e9276465d4a5fe80fbf..420083f019cf207e36de993f46073336e31233b1 100644 --- a/drivers/media/platform/msm/ais/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/ais/fd/msm_fd_dev.c @@ -430,7 +430,6 @@ static int msm_fd_open(struct file *file) ctx->vb2_q.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ctx->vb2_q.io_modes = VB2_USERPTR; ctx->vb2_q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - mutex_init(&ctx->lock); ret = vb2_queue_init(&ctx->vb2_q); if (ret < 0) { dev_err(device->dev, "Error queue init\n"); @@ -481,9 +480,7 @@ static int msm_fd_release(struct file *file) msm_cpp_vbif_register_error_handler((void *)ctx, VBIF_CLIENT_FD, NULL); - mutex_lock(&ctx->lock); vb2_queue_release(&ctx->vb2_q); - mutex_unlock(&ctx->lock); vfree(ctx->stats); @@ -513,9 +510,7 @@ static unsigned int msm_fd_poll(struct file *file, struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data); unsigned int ret; - mutex_lock(&ctx->lock); ret = vb2_poll(&ctx->vb2_q, file, wait); - mutex_unlock(&ctx->lock); if (atomic_read(&ctx->subscribed_for_event)) { poll_wait(file, &ctx->fh.wait, wait); @@ -753,9 +748,9 @@ static int msm_fd_reqbufs(struct file *file, int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - mutex_lock(&ctx->lock); + mutex_lock(&ctx->fd_device->recovery_lock); ret = vb2_reqbufs(&ctx->vb2_q, req); - mutex_unlock(&ctx->lock); + mutex_unlock(&ctx->fd_device->recovery_lock); return ret; } @@ -771,9 +766,9 @@ static int msm_fd_qbuf(struct file *file, void *fh, int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - mutex_lock(&ctx->lock); + mutex_lock(&ctx->fd_device->recovery_lock); ret = vb2_qbuf(&ctx->vb2_q, pb); - mutex_unlock(&ctx->lock); + mutex_unlock(&ctx->fd_device->recovery_lock); return ret; } @@ -790,9 +785,9 @@ static int msm_fd_dqbuf(struct file *file, int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - mutex_lock(&ctx->lock); + mutex_lock(&ctx->fd_device->recovery_lock); ret = vb2_dqbuf(&ctx->vb2_q, pb, file->f_flags & O_NONBLOCK); - mutex_unlock(&ctx->lock); + mutex_unlock(&ctx->fd_device->recovery_lock); return ret; } @@ -808,9 +803,7 @@ static int msm_fd_streamon(struct file *file, struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); int ret; - mutex_lock(&ctx->lock); ret = vb2_streamon(&ctx->vb2_q, buf_type); - mutex_unlock(&ctx->lock); if (ret < 0) dev_err(ctx->fd_device->dev, "Stream on fails\n"); @@ -829,9 +822,7 @@ static int msm_fd_streamoff(struct file *file, struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); int ret; - mutex_lock(&ctx->lock); ret = vb2_streamoff(&ctx->vb2_q, buf_type); - mutex_unlock(&ctx->lock); if (ret < 0) dev_err(ctx->fd_device->dev, "Stream off fails\n"); @@ -1062,18 +1053,14 @@ static int msm_fd_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) a->value = ctx->format.size->work_size; break; case V4L2_CID_FD_WORK_MEMORY_FD: - mutex_lock(&ctx->fd_device->recovery_lock); if (ctx->work_buf.fd != -1) msm_fd_hw_unmap_buffer(&ctx->work_buf); if (a->value >= 0) { ret = msm_fd_hw_map_buffer(&ctx->mem_pool, a->value, &ctx->work_buf); - if (ret < 0) { - mutex_unlock(&ctx->fd_device->recovery_lock); + if (ret < 0) return ret; - } } - mutex_unlock(&ctx->fd_device->recovery_lock); break; default: return -EINVAL; diff --git a/drivers/media/platform/msm/ais/fd/msm_fd_dev.h b/drivers/media/platform/msm/ais/fd/msm_fd_dev.h index a7615a65d2fcf0d7ab9644e92c9aa69d3782a9c6..c15032256f4db5ee2a37e5fc91d5743cf973789c 100644 --- a/drivers/media/platform/msm/ais/fd/msm_fd_dev.h +++ b/drivers/media/platform/msm/ais/fd/msm_fd_dev.h @@ -161,7 +161,6 @@ struct fd_ctx { struct msm_fd_mem_pool mem_pool; struct msm_fd_stats *stats; struct msm_fd_buf_handle work_buf; - struct mutex lock; }; /* diff --git a/drivers/media/platform/msm/ais/isp/msm_isp.h b/drivers/media/platform/msm/ais/isp/msm_isp.h index 86974eeb4a3230e96a26a99afbfe53786fd95391..72a76d178aa858d17987d9a026f7dd02735e944f 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp.h +++ b/drivers/media/platform/msm/ais/isp/msm_isp.h @@ -355,7 +355,6 @@ struct msm_vfe_hardware_info { uint32_t dmi_reg_offset; uint32_t min_ab; uint32_t min_ib; - uint32_t regulator_num; const char *regulator_names[]; }; diff --git a/drivers/media/platform/msm/ais/isp/msm_isp47.c b/drivers/media/platform/msm/ais/isp/msm_isp47.c index 04e879fc3bcfd129e03e61f220d5b59ef145b9e6..d63282f80aca9e8bbcef1f1db8f98913cec4d402 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp47.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp47.c @@ -699,12 +699,6 @@ void msm_vfe47_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { - if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { - pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); - spin_unlock_irqrestore(&vfe_dev->reg_update_lock, - flags); - return; - } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res-> vfe_base[ISP_VFE0] + 0x4AC); @@ -2543,7 +2537,8 @@ int msm_vfe47_get_regulators(struct vfe_device *vfe_dev) int rc = 0; int i; - vfe_dev->vfe_num_regulators = vfe_dev->hw_info->regulator_num; + vfe_dev->vfe_num_regulators = + sizeof(*vfe_dev->hw_info->regulator_names) / sizeof(char *); vfe_dev->regulator_info = kzalloc(sizeof(struct msm_cam_regulator) * vfe_dev->vfe_num_regulators, GFP_KERNEL); @@ -2816,7 +2811,6 @@ struct msm_vfe_hardware_info vfe47_hw_info = { .dmi_reg_offset = 0xC2C, .axi_hw_info = &msm_vfe47_axi_hw_info, .stats_hw_info = &msm_vfe47_stats_hw_info, - .regulator_num = 3, .regulator_names = {"vdd", "camss-vdd", "mmagic-vdd"}, }; EXPORT_SYMBOL(vfe47_hw_info); diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/ais/isp/msm_isp_stats_util.c index 0d08cffda25c46ccbb53980838c9080a4f351228..6e89544161ee00e7d280135a9fe1611b9f5e60ae 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp_stats_util.c @@ -891,12 +891,6 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL; struct msm_isp_sw_framskip *sw_skip_info = NULL; - if (update_cmd->num_streams > MSM_ISP_STATS_MAX) { - pr_err("%s: Invalid num_streams %d\n", - __func__, update_cmd->num_streams); - return -EINVAL; - } - /* validate request */ for (i = 0; i < update_cmd->num_streams; i++) { update_info = (struct msm_vfe_axi_stream_cfg_update_info *) diff --git a/drivers/media/platform/msm/ais/ispif/msm_ispif.c b/drivers/media/platform/msm/ais/ispif/msm_ispif.c index c41f4546da5f84be14a464f5887d855fa012fb10..8eb88364a2cb974f1e193735e60a42ec18f91ecf 100644 --- a/drivers/media/platform/msm/ais/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/ais/ispif/msm_ispif.c @@ -69,11 +69,6 @@ static void msm_ispif_io_dump_reg(struct ispif_device *ispif) { if (!ispif->enb_dump_reg) return; - if (!ispif->base) { - pr_err("%s: null pointer for the ispif base\n", __func__); - return; - } - msm_camera_io_dump(ispif->base, 0x250, 0); } diff --git a/drivers/media/platform/msm/ais/msm.c b/drivers/media/platform/msm/ais/msm.c index 902e05b3329bf67ebb1f0fa9c8e8d058e79ad476..3c2e28eaa4f93cb68cd414cf18da9fa5f8d1d1af 100644 --- a/drivers/media/platform/msm/ais/msm.c +++ b/drivers/media/platform/msm/ais/msm.c @@ -292,7 +292,6 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) return; while (1) { - unsigned long wl_flags; if (try_count > 5) { pr_err("%s : not able to delete stream %d\n", @@ -300,20 +299,18 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) break; } - write_lock_irqsave(&session->stream_rwlock, wl_flags); + write_lock(&session->stream_rwlock); try_count++; stream = msm_queue_find(&session->stream_q, struct msm_stream, list, __msm_queue_find_stream, &stream_id); if (!stream) { - write_unlock_irqrestore(&session->stream_rwlock, - wl_flags); + write_unlock(&session->stream_rwlock); return; } if (msm_vb2_get_stream_state(stream) != 1) { - write_unlock_irqrestore(&session->stream_rwlock, - wl_flags); + write_unlock(&session->stream_rwlock); continue; } @@ -323,7 +320,7 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) kfree(stream); stream = NULL; spin_unlock_irqrestore(&(session->stream_q.lock), flags); - write_unlock_irqrestore(&session->stream_rwlock, wl_flags); + write_unlock(&session->stream_rwlock); break; } @@ -394,9 +391,6 @@ static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev, struct msm_sd_subdev *temp_sd; list_for_each_entry(temp_sd, sd_list, list) { - if (temp_sd == msm_subdev) { - return; - } if (msm_subdev->close_seq < temp_sd->close_seq) { list_add_tail(&msm_subdev->list, &temp_sd->list); return; @@ -731,19 +725,6 @@ static long msm_private_ioctl(struct file *file, void *fh, return 0; } - if (!event_data) - return -EINVAL; - - switch (cmd) { - case MSM_CAM_V4L2_IOCTL_NOTIFY: - case MSM_CAM_V4L2_IOCTL_CMD_ACK: - case MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG: - case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR: - break; - default: - return -ENOTTY; - } - memset(&event, 0, sizeof(struct v4l2_event)); session_id = event_data->session_id; stream_id = event_data->stream_id; diff --git a/drivers/media/platform/msm/ais/msm.h b/drivers/media/platform/msm/ais/msm.h index ff3008ec6872f658690b671d49d56130634b1c86..5d456310c3014376bb447e2d12af66a924bcea83 100644 --- a/drivers/media/platform/msm/ais/msm.h +++ b/drivers/media/platform/msm/ais/msm.h @@ -46,7 +46,6 @@ extern bool is_daemon_status; struct msm_video_device { struct video_device *vdev; atomic_t opened; - struct mutex video_drvdata_mutex; }; struct msm_queue_head { diff --git a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c index 1cbc49c8485cfbd56df18caad47487a0df079c8d..36aa3f62fbec7283c6b7b77c34766b0ac45ecbff 100644 --- a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c @@ -47,23 +47,22 @@ static int msm_vb2_buf_init(struct vb2_buffer *vb) struct msm_session *session; struct msm_vb2_buffer *msm_vb2_buf; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - unsigned long rl_flags; session = msm_get_session_from_vb2q(vb->vb2_queue); if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s: Couldn't find stream\n", __func__); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } msm_vb2_buf = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); msm_vb2_buf->in_freeq = 0; - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return 0; } @@ -72,7 +71,7 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; - unsigned long flags, rl_flags; + unsigned long flags; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); @@ -85,19 +84,19 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) if (IS_ERR_OR_NULL(session)) return; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return; } spin_lock_irqsave(&stream->stream_lock, flags); list_add_tail(&msm_vb2->list, &stream->queued_list); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); } static void msm_vb2_buf_finish(struct vb2_buffer *vb) @@ -105,7 +104,7 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; - unsigned long flags, rl_flags; + unsigned long flags; struct msm_vb2_buffer *msm_vb2_entry, *temp; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -119,12 +118,12 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) if (IS_ERR_OR_NULL(session)) return; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return; } @@ -137,7 +136,7 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) } } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); } static void msm_vb2_stop_stream(struct vb2_queue *q) @@ -145,19 +144,19 @@ static void msm_vb2_stop_stream(struct vb2_queue *q) struct msm_vb2_buffer *msm_vb2, *temp; struct msm_stream *stream; struct msm_session *session; - unsigned long flags, rl_flags; + unsigned long flags; struct vb2_v4l2_buffer *vb2_v4l2_buf; session = msm_get_session_from_vb2q(q); if (IS_ERR_OR_NULL(session)) return; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream_from_vb2q(q); if (!stream) { pr_err_ratelimited("%s:%d] NULL stream", __func__, __LINE__); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return; } @@ -177,7 +176,7 @@ static void msm_vb2_stop_stream(struct vb2_queue *q) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); } int msm_vb2_get_stream_state(struct msm_stream *stream) @@ -256,17 +255,17 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_session *session; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags, rl_flags; + unsigned long flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return NULL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return NULL; } @@ -292,7 +291,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return vb2_v4l2_buf; } @@ -303,18 +302,18 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_session *session; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags, rl_flags; + unsigned long flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return NULL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return NULL; } @@ -338,7 +337,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return vb2_v4l2_buf; } @@ -350,17 +349,17 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, struct msm_vb2_buffer *msm_vb2; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; int rc = 0; - unsigned long flags, rl_flags; + unsigned long flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } @@ -375,8 +374,6 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, pr_err("VB buffer is INVALID vb=%pK, ses_id=%d, str_id=%d\n", vb, session_id, stream_id); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, - rl_flags); return -EINVAL; } msm_vb2 = @@ -393,7 +390,7 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return rc; } @@ -401,7 +398,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, unsigned int stream_id, uint32_t sequence, struct timeval *ts, uint32_t reserved) { - unsigned long flags, rl_flags; + unsigned long flags; struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; @@ -412,11 +409,11 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } @@ -431,8 +428,6 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%pK\n", session_id, stream_id, vb); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, - rl_flags); return -EINVAL; } msm_vb2 = container_of(vb2_v4l2_buf, @@ -453,7 +448,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return rc; } @@ -464,18 +459,18 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_session *session; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags, rl_flags; + unsigned long flags; long rc = -EINVAL; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return rc; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } @@ -504,14 +499,14 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return rc; } EXPORT_SYMBOL(msm_vb2_return_buf_by_idx); static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) { - unsigned long flags, rl_flags; + unsigned long flags; struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; @@ -521,11 +516,11 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } @@ -537,7 +532,7 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return 0; } diff --git a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c index 6c50070c91ab84840c3e0871a42f1464a5cfd433..811ac98beead069244e07ad10821f13d53840304 100644 --- a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c @@ -2882,7 +2882,7 @@ end: return rc; } -static int msm_cpp_validate_ioctl_input(unsigned int cmd, void *arg, +static int msm_cpp_validate_input(unsigned int cmd, void *arg, struct msm_camera_v4l2_ioctl_t **ioctl_ptr) { switch (cmd) { @@ -2922,14 +2922,6 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, pr_err("sd %pK\n", sd); return -EINVAL; } - - - rc = msm_cpp_validate_ioctl_input(cmd, arg, &ioctl_ptr); - if (rc != 0) { - pr_err("input validation failed\n"); - return rc; - } - cpp_dev = v4l2_get_subdevdata(sd); if (cpp_dev == NULL) { pr_err("cpp_dev is null\n"); @@ -2941,6 +2933,11 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, return -EINVAL; } + rc = msm_cpp_validate_input(cmd, arg, &ioctl_ptr); + if (rc != 0) { + pr_err("input validation failed\n"); + return rc; + } mutex_lock(&cpp_dev->mutex); CPP_DBG("E cmd: 0x%x\n", cmd); @@ -3440,7 +3437,6 @@ STREAM_BUFF_END: } else { pr_err("%s:%d IOMMMU attach triggered in invalid state\n", __func__, __LINE__); - rc = -EINVAL; } break; } @@ -4065,8 +4061,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, default: pr_err_ratelimited("%s: unsupported compat type :%x LOAD %lu\n", __func__, cmd, VIDIOC_MSM_CPP_LOAD_FIRMWARE); - mutex_unlock(&cpp_dev->mutex); - return -EINVAL; + break; } mutex_unlock(&cpp_dev->mutex); @@ -4097,7 +4092,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, default: pr_err_ratelimited("%s: unsupported compat type :%d\n", __func__, cmd); - return -EINVAL; + break; } if (is_copytouser_req) { diff --git a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c index 40806d5a164f6d4f37c98d708db50dd0200e57bd..1adb380f335f5d811259b3bc773b71195c2edf5b 100644 --- a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c @@ -1722,10 +1722,6 @@ static long msm_actuator_subdev_do_ioctl( parg = &actuator_data; break; } - break; - case VIDIOC_MSM_ACTUATOR_CFG: - pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd); - return -EINVAL; } rc = msm_actuator_subdev_ioctl(sd, cmd, parg); diff --git a/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c b/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c index e4f534859bf2647471ab7a7cc9878f47d89c4c55..6af589e5c230a496d452dd4015e98b70058a1e9e 100644 --- a/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/ais/sensor/flash/msm_flash.c @@ -152,13 +152,6 @@ static int32_t msm_flash_i2c_write_table( conf_array.reg_setting = settings->reg_setting_a; conf_array.size = settings->size; - /* Validate the settings size */ - if ((!conf_array.size) || (conf_array.size > MAX_I2C_REG_SET)) { - pr_err("failed: invalid size %d", conf_array.size); - return -EINVAL; - } - - return flash_ctrl->flash_i2c_client.i2c_func_tbl->i2c_write_table( &flash_ctrl->flash_i2c_client, &conf_array); } @@ -504,46 +497,23 @@ static int32_t msm_flash_init( } flash_ctrl->flash_state = MSM_CAMERA_FLASH_INIT; + CDBG("Exit"); return 0; } +#ifdef CONFIG_COMPAT static int32_t msm_flash_init_prepare( struct msm_flash_ctrl_t *flash_ctrl, struct msm_flash_cfg_data_t *flash_data) { - #ifdef CONFIG_COMPAT - struct msm_flash_cfg_data_t flash_data_k; - struct msm_flash_init_info_t flash_init_info; - int32_t i = 0; - - if (!is_compat_task()) { - /*for 64-bit usecase,it need copy the data to local memory*/ - flash_data_k.cfg_type = flash_data->cfg_type; - for (i = 0; i < MAX_LED_TRIGGERS; i++) { - flash_data_k.flash_current[i] = - flash_data->flash_current[i]; - flash_data_k.flash_duration[i] = - flash_data->flash_duration[i]; - } - - flash_data_k.cfg.flash_init_info = &flash_init_info; - if (copy_from_user(&flash_init_info, - (void __user *)(flash_data->cfg.flash_init_info), - sizeof(struct msm_flash_init_info_t))) { - pr_err("%s copy_from_user failed %d\n", - __func__, __LINE__); - return -EFAULT; - } - return msm_flash_init(flash_ctrl, &flash_data_k); - } - /* - * for 32-bit usecase,it already copy the userspace - * data to local memory in msm_flash_subdev_do_ioctl() - * so here do not need copy from user - */ return msm_flash_init(flash_ctrl, flash_data); +} #else +static int32_t msm_flash_init_prepare( + struct msm_flash_ctrl_t *flash_ctrl, + struct msm_flash_cfg_data_t *flash_data) +{ struct msm_flash_cfg_data_t flash_data_k; struct msm_flash_init_info_t flash_init_info; int32_t i = 0; @@ -558,15 +528,15 @@ static int32_t msm_flash_init_prepare( flash_data_k.cfg.flash_init_info = &flash_init_info; if (copy_from_user(&flash_init_info, - (void __user *)(flash_data->cfg.flash_init_info), + (void *)(flash_data->cfg.flash_init_info), sizeof(struct msm_flash_init_info_t))) { pr_err("%s copy_from_user failed %d\n", __func__, __LINE__); return -EFAULT; } return msm_flash_init(flash_ctrl, &flash_data_k); -#endif } +#endif static int32_t msm_flash_low( struct msm_flash_ctrl_t *flash_ctrl, @@ -1052,13 +1022,13 @@ static long msm_flash_subdev_do_ioctl( sd = vdev_to_v4l2_subdev(vdev); u32 = (struct msm_flash_cfg_data_t32 *)arg; + flash_data.cfg_type = u32->cfg_type; + for (i = 0; i < MAX_LED_TRIGGERS; i++) { + flash_data.flash_current[i] = u32->flash_current[i]; + flash_data.flash_duration[i] = u32->flash_duration[i]; + } switch (cmd) { case VIDIOC_MSM_FLASH_CFG32: - flash_data.cfg_type = u32->cfg_type; - for (i = 0; i < MAX_LED_TRIGGERS; i++) { - flash_data.flash_current[i] = u32->flash_current[i]; - flash_data.flash_duration[i] = u32->flash_duration[i]; - } cmd = VIDIOC_MSM_FLASH_CFG; switch (flash_data.cfg_type) { case CFG_FLASH_OFF: @@ -1092,9 +1062,6 @@ static long msm_flash_subdev_do_ioctl( break; } break; - case VIDIOC_MSM_FLASH_CFG: - pr_err("invalid cmd 0x%x received\n", cmd); - return -EINVAL; default: return msm_flash_subdev_ioctl(sd, cmd, arg); } diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c index 58bddb1a3fbab7b200e8846d1f872a29738f9f57..c02972e5e993df877a836e0b42607f6d38a62de5 100644 --- a/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c @@ -105,11 +105,7 @@ static int32_t msm_sensor_driver_create_i2c_v4l_subdev s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; s_ctrl->sensordata->sensor_info->session_id = session_id; s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; - rc = msm_sd_register(&s_ctrl->msm_sd); - if (rc < 0) { - pr_err("failed: msm_sd_register rc %d", rc); - return rc; - } + msm_sd_register(&s_ctrl->msm_sd); msm_sensor_v4l2_subdev_fops = v4l2_subdev_fops; #ifdef CONFIG_COMPAT msm_sensor_v4l2_subdev_fops.compat_ioctl32 = @@ -137,11 +133,7 @@ static int32_t msm_sensor_driver_create_v4l_subdev s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; - rc = msm_sd_register(&s_ctrl->msm_sd); - if (rc < 0) { - pr_err("failed: msm_sd_register rc %d", rc); - return rc; - } + msm_sd_register(&s_ctrl->msm_sd); msm_cam_copy_v4l2_subdev_fops(&msm_sensor_v4l2_subdev_fops); #ifdef CONFIG_COMPAT msm_sensor_v4l2_subdev_fops.compat_ioctl32 = @@ -896,6 +888,11 @@ CSID_TG: pr_err("%s probe succeeded", slave_info->sensor_name); + /* Set probe succeeded flag to 1 so that no other camera shall + * probed on this slot + */ + s_ctrl->is_probe_succeed = 1; + /* * Update the subdevice id of flash-src based on availability in kernel. */ @@ -934,10 +931,6 @@ CSID_TG: msm_sensor_fill_sensor_info(s_ctrl, probed_info, entity_name); - /* Set probe succeeded flag to 1 so that no other camera shall - * probed on this slot - */ - s_ctrl->is_probe_succeed = 1; return rc; free_camera_info: diff --git a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c b/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c index 3dccb73d9de4772c30666709704e6ff8f7f5bfbe..28a5402a4359ec2ce7b5f74a0f3f5fb840db61e6 100644 --- a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c +++ b/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c @@ -623,13 +623,11 @@ static long msm_ois_subdev_ioctl(struct v4l2_subdev *sd, pr_err("o_ctrl->i2c_client.i2c_func_tbl NULL\n"); return -EINVAL; } - mutex_lock(o_ctrl->ois_mutex); rc = msm_ois_power_down(o_ctrl); if (rc < 0) { pr_err("%s:%d OIS Power down failed\n", __func__, __LINE__); } - mutex_unlock(o_ctrl->ois_mutex); return msm_ois_close(sd, NULL); default: return -ENOIOCTLCMD; @@ -783,11 +781,11 @@ static long msm_ois_subdev_do_ioctl( u32 = (struct msm_ois_cfg_data32 *)arg; parg = arg; + ois_data.cfgtype = u32->cfgtype; switch (cmd) { case VIDIOC_MSM_OIS_CFG32: cmd = VIDIOC_MSM_OIS_CFG; - ois_data.cfgtype = u32->cfgtype; switch (u32->cfgtype) { case CFG_OIS_CONTROL: @@ -821,6 +819,7 @@ static long msm_ois_subdev_do_ioctl( settings.reg_setting = compat_ptr(settings32.reg_setting); + ois_data.cfgtype = u32->cfgtype; ois_data.cfg.settings = &settings; parg = &ois_data; break; @@ -828,10 +827,6 @@ static long msm_ois_subdev_do_ioctl( parg = &ois_data; break; } - break; - case VIDIOC_MSM_OIS_CFG: - pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd); - return -EINVAL; } rc = msm_ois_subdev_ioctl(sd, cmd, parg); diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig index 568f817e8614ceca298db1e823eb62bc9c2781c3..6d3f9c5b6f23c2a099e385e7023ad4d609c25741 100644 --- a/drivers/media/platform/msm/camera_v2/Kconfig +++ b/drivers/media/platform/msm/camera_v2/Kconfig @@ -203,6 +203,23 @@ config OV12830 snapshot config = 4224 * 3000 at 15 fps. 2 lanes max fps is 18, 4 lanes max fps is 24. +config SONY_CAM_V4L2 + bool "SONY specific camera" + depends on MSMB_CAMERA + default n + ---help--- + SONY specific camera module + +config FRONT_CAMERA_LED_SCALE + int "Reduce RGB LED brightness when front camera is active" + depends on SONY_CAM_V4L2 && LEDS_QPNP_RGB_SCALE + range 0 99 + default 0 + ---help--- + Reduce the brightness of front RGB LED by specified percentage + when front camera sensor is powered on. Set it to zero to disable + the feature. + config MSM_V4L2_VIDEO_OVERLAY_DEVICE tristate "QTI MSM V4l2 video overlay device" ---help--- diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c index 4f1c73941eafa08940ed997bde0ad97b5eff5819..df0664b496ba799ebe8bbb5e99b0d6cfb5939c90 100644 --- a/drivers/media/platform/msm/camera_v2/camera/camera.c +++ b/drivers/media/platform/msm/camera_v2/camera/camera.c @@ -572,10 +572,10 @@ static int camera_v4l2_fh_release(struct file *filep) if (sp) { v4l2_fh_del(&sp->fh); v4l2_fh_exit(&sp->fh); - mutex_destroy(&sp->lock); - kzfree(sp); } + mutex_destroy(&sp->lock); + kzfree(sp); return 0; } @@ -623,7 +623,6 @@ static int camera_v4l2_open(struct file *filep) unsigned long opn_idx, idx; BUG_ON(!pvdev); - mutex_lock(&pvdev->video_drvdata_mutex); rc = camera_v4l2_fh_open(filep); if (rc < 0) { pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n", @@ -694,7 +693,6 @@ static int camera_v4l2_open(struct file *filep) idx |= (1 << find_first_zero_bit((const unsigned long *)&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); atomic_cmpxchg(&pvdev->opened, opn_idx, idx); - mutex_unlock(&pvdev->video_drvdata_mutex); return rc; @@ -709,7 +707,6 @@ stream_fail: vb2_q_fail: camera_v4l2_fh_release(filep); fh_open_fail: - mutex_unlock(&pvdev->video_drvdata_mutex); return rc; } @@ -740,7 +737,6 @@ static int camera_v4l2_close(struct file *filep) if (WARN_ON(!session)) return -EIO; - mutex_lock(&pvdev->video_drvdata_mutex); mutex_lock(&session->close_lock); opn_idx = atomic_read(&pvdev->opened); mask = (1 << sp->stream_id); @@ -782,7 +778,6 @@ static int camera_v4l2_close(struct file *filep) } camera_v4l2_fh_release(filep); - mutex_unlock(&pvdev->video_drvdata_mutex); return 0; } @@ -929,7 +924,6 @@ int camera_init_v4l2(struct device *dev, unsigned int *session) *session = pvdev->vdev->num; atomic_set(&pvdev->opened, 0); - mutex_init(&pvdev->video_drvdata_mutex); video_set_drvdata(pvdev->vdev, pvdev); device_init_wakeup(&pvdev->vdev->dev, 1); goto init_end; diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c index 8a49c7cf9f4ada0ee8bf78fa6b8d60a08e185ce5..fe14f8dcaef254f34a1c2b9f3e49aa9fc87d048f 100644 --- a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c +++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, 2017, The Linux Foundataion. All rights reserved. +/* Copyright (c) 2011-2014, The Linux Foundataion. 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 @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -23,6 +28,9 @@ #define BUFF_SIZE_128 128 #undef CDBG +#if defined(CONFIG_SONY_CAM_V4L2) +#define CDBG(fmt, args...) +#else #define CDBG(fmt, args...) pr_debug(fmt, ##args) void msm_camera_io_w(u32 data, void __iomem *addr) @@ -30,6 +38,7 @@ void msm_camera_io_w(u32 data, void __iomem *addr) CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); writel_relaxed((data), (addr)); } +#endif /* This API is to write a block of data * to same address @@ -45,7 +54,11 @@ int32_t msm_camera_io_w_block(const u32 *addr, void __iomem *base, for (i = 0; i < len; i++) { CDBG("%s: len =%d val=%x base =%pK\n", __func__, len, addr[i], base); +#if defined(CONFIG_SONY_CAM_V4L2) + writel_relaxed_no_log(addr[i], base); +#else writel_relaxed(addr[i], base); +#endif } return 0; } @@ -64,7 +77,11 @@ int32_t msm_camera_io_w_reg_block(const u32 *addr, void __iomem *base, for (i = 0; i < len; i = i + 2) { CDBG("%s: len =%d val=%x base =%pK reg=%x\n", __func__, len, addr[i + 1], base, addr[i]); +#if defined(CONFIG_SONY_CAM_V4L2) + writel_relaxed_no_log(addr[i + 1], base + addr[i]); +#else writel_relaxed(addr[i + 1], base + addr[i]); +#endif } return 0; } @@ -74,7 +91,11 @@ void msm_camera_io_w_mb(u32 data, void __iomem *addr) CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); /* ensure write is done */ wmb(); +#if defined(CONFIG_SONY_CAM_V4L2) + writel_relaxed_no_log((data), (addr)); +#else writel_relaxed((data), (addr)); +#endif /* ensure write is done */ wmb(); } @@ -91,13 +112,18 @@ int32_t msm_camera_io_w_mb_block(const u32 *addr, void __iomem *base, u32 len) wmb(); CDBG("%s: len =%d val=%x base =%pK\n", __func__, len, addr[i], base); +#if defined(CONFIG_SONY_CAM_V4L2) + writel_relaxed_no_log(addr[i], base); +#else writel_relaxed(addr[i], base); +#endif } /* ensure last write is done */ wmb(); return 0; } +#if !defined(CONFIG_SONY_CAM_V4L2) u32 msm_camera_io_r(void __iomem *addr) { uint32_t data = readl_relaxed(addr); @@ -105,6 +131,7 @@ u32 msm_camera_io_r(void __iomem *addr) CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data)); return data; } +#endif u32 msm_camera_io_r_mb(void __iomem *addr) { @@ -126,7 +153,11 @@ void msm_camera_io_memcpy_toio(void __iomem *dest_addr, u32 *s = (u32 *) src_addr; for (i = 0; i < len; i++) +#if defined(CONFIG_SONY_CAM_V4L2) + writel_relaxed_no_log(*s++, d++); +#else writel_relaxed(*s++, d++); +#endif } int32_t msm_camera_io_poll_value(void __iomem *addr, u32 wait_data, u32 retry, @@ -175,45 +206,35 @@ int32_t msm_camera_io_poll_value_wmask(void __iomem *addr, u32 wait_data, void msm_camera_io_dump(void __iomem *addr, int size, int enable) { - char line_str[128]; + char line_str[128], *p_str; int i; - ptrdiff_t p = 0; - size_t offset = 0, used = 0; + u32 *p = (u32 *) addr; u32 data; CDBG("%s: addr=%pK size=%d\n", __func__, addr, size); - if (!addr || (size <= 0) || !enable) + if (!p || (size <= 0) || !enable) return; line_str[0] = '\0'; + p_str = line_str; for (i = 0; i < size/4; i++) { if (i % 4 == 0) { - used = snprintf(line_str + offset, - sizeof(line_str) - offset, "0x%04tX: ", p); - if (offset + used >= sizeof(line_str)) { - pr_err("%s\n", line_str); - offset = 0; - line_str[0] = '\0'; - } else { - offset += used; - } - } - data = readl_relaxed(addr + p); - p = p + 4; - used = snprintf(line_str + offset, - sizeof(line_str) - offset, "%08x ", data); - if (offset + used >= sizeof(line_str)) { - pr_err("%s\n", line_str); - offset = 0; - line_str[0] = '\0'; - } else { - offset += used; +#ifdef CONFIG_COMPAT + snprintf(p_str, 20, "%016lx: ", (unsigned long) p); + p_str += 18; +#else + snprintf(p_str, 12, "%08lx: ", (unsigned long) p); + p_str += 10; +#endif } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%08x ", data); + p_str += 9; if ((i + 1) % 4 == 0) { pr_err("%s\n", line_str); line_str[0] = '\0'; - offset = 0; + p_str = line_str; } } if (line_str[0] != '\0') @@ -424,7 +445,7 @@ int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, curr_vreg = &cam_vreg[j]; reg_ptr[j] = regulator_get(dev, curr_vreg->reg_name); - if (IS_ERR_OR_NULL(reg_ptr[j])) { + if (IS_ERR(reg_ptr[j])) { pr_err("%s: %s get failed\n", __func__, curr_vreg->reg_name); @@ -531,7 +552,7 @@ int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, continue; } else j = i; - if (IS_ERR_OR_NULL(reg_ptr[j])) { + if (IS_ERR(reg_ptr[j])) { pr_err("%s: %s null regulator\n", __func__, cam_vreg[j].reg_name); goto disable_vreg; @@ -556,16 +577,12 @@ int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, continue; } else j = i; - if (reg_ptr[j]) { - regulator_disable(reg_ptr[j]); - if (cam_vreg[j].delay > 20) - msleep(cam_vreg[j].delay); - else if (cam_vreg[j].delay) - usleep_range( - cam_vreg[j].delay * 1000, - (cam_vreg[j].delay * 1000) - + 1000); - } + regulator_disable(reg_ptr[j]); + if (cam_vreg[j].delay > 20) + msleep(cam_vreg[j].delay); + else if (cam_vreg[j].delay) + usleep_range(cam_vreg[j].delay * 1000, + (cam_vreg[j].delay * 1000) + 1000); } } return rc; diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.h b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.h index 04c8822330f04dfc2b60f799099eab8601ec28ca..b85884c7849472a1c5c5432c6048df163575949b 100644 --- a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.h +++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __MSM_CAMERA_IO_UTIL_H #define __MSM_CAMERA_IO_UTIL_H @@ -16,6 +21,9 @@ #include #include #include +#if defined(CONFIG_SONY_CAM_V4L2) +#include +#endif #include #include #include @@ -36,9 +44,25 @@ struct msm_cam_dump_string_info { uint32_t offset; }; +#if defined(CONFIG_SONY_CAM_V4L2) +static inline void msm_camera_io_w(u32 data, void __iomem *addr) +{ + writel_relaxed_no_log((data), (addr)); +} +#else void msm_camera_io_w(u32 data, void __iomem *addr); +#endif void msm_camera_io_w_mb(u32 data, void __iomem *addr); +#if defined(CONFIG_SONY_CAM_V4L2) +static inline u32 msm_camera_io_r(void __iomem *addr) +{ + uint32_t data = readl_relaxed_no_log(addr); + + return data; +} +#else u32 msm_camera_io_r(void __iomem *addr); +#endif u32 msm_camera_io_r_mb(void __iomem *addr); void msm_camera_io_dump(void __iomem *addr, int size, int enable); void msm_camera_io_memcpy(void __iomem *dest_addr, diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c index d881b4aea48f7653b6fd2b5ee204999e9da652db..a04d7ca73fe10446f6c1e31822af755d38a991d2 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c @@ -434,7 +434,6 @@ static int msm_fd_open(struct file *file) ctx->vb2_q.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ctx->vb2_q.io_modes = VB2_USERPTR; ctx->vb2_q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - mutex_init(&ctx->lock); ret = vb2_queue_init(&ctx->vb2_q); if (ret < 0) { dev_err(device->dev, "Error queue init\n"); @@ -485,9 +484,7 @@ static int msm_fd_release(struct file *file) msm_cpp_vbif_register_error_handler((void *)ctx, VBIF_CLIENT_FD, NULL); - mutex_lock(&ctx->lock); vb2_queue_release(&ctx->vb2_q); - mutex_unlock(&ctx->lock); vfree(ctx->stats); @@ -517,9 +514,7 @@ static unsigned int msm_fd_poll(struct file *file, struct fd_ctx *ctx = msm_fd_ctx_from_fh(file->private_data); unsigned int ret; - mutex_lock(&ctx->lock); ret = vb2_poll(&ctx->vb2_q, file, wait); - mutex_unlock(&ctx->lock); if (atomic_read(&ctx->subscribed_for_event)) { poll_wait(file, &ctx->fh.wait, wait); @@ -757,9 +752,9 @@ static int msm_fd_reqbufs(struct file *file, int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - mutex_lock(&ctx->lock); + mutex_lock(&ctx->fd_device->recovery_lock); ret = vb2_reqbufs(&ctx->vb2_q, req); - mutex_unlock(&ctx->lock); + mutex_unlock(&ctx->fd_device->recovery_lock); return ret; } @@ -775,9 +770,9 @@ static int msm_fd_qbuf(struct file *file, void *fh, int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - mutex_lock(&ctx->lock); + mutex_lock(&ctx->fd_device->recovery_lock); ret = vb2_qbuf(&ctx->vb2_q, pb); - mutex_unlock(&ctx->lock); + mutex_unlock(&ctx->fd_device->recovery_lock); return ret; } @@ -794,9 +789,9 @@ static int msm_fd_dqbuf(struct file *file, int ret; struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); - mutex_lock(&ctx->lock); + mutex_lock(&ctx->fd_device->recovery_lock); ret = vb2_dqbuf(&ctx->vb2_q, pb, file->f_flags & O_NONBLOCK); - mutex_unlock(&ctx->lock); + mutex_unlock(&ctx->fd_device->recovery_lock); return ret; } @@ -812,9 +807,7 @@ static int msm_fd_streamon(struct file *file, struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); int ret; - mutex_lock(&ctx->lock); ret = vb2_streamon(&ctx->vb2_q, buf_type); - mutex_unlock(&ctx->lock); if (ret < 0) dev_err(ctx->fd_device->dev, "Stream on fails\n"); @@ -833,9 +826,7 @@ static int msm_fd_streamoff(struct file *file, struct fd_ctx *ctx = msm_fd_ctx_from_fh(fh); int ret; - mutex_lock(&ctx->lock); ret = vb2_streamoff(&ctx->vb2_q, buf_type); - mutex_unlock(&ctx->lock); if (ret < 0) dev_err(ctx->fd_device->dev, "Stream off fails\n"); @@ -1066,18 +1057,14 @@ static int msm_fd_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) a->value = ctx->format.size->work_size; break; case V4L2_CID_FD_WORK_MEMORY_FD: - mutex_lock(&ctx->fd_device->recovery_lock); if (ctx->work_buf.fd != -1) msm_fd_hw_unmap_buffer(&ctx->work_buf); if (a->value >= 0) { ret = msm_fd_hw_map_buffer(&ctx->mem_pool, a->value, &ctx->work_buf); - if (ret < 0) { - mutex_unlock(&ctx->fd_device->recovery_lock); + if (ret < 0) return ret; - } } - mutex_unlock(&ctx->fd_device->recovery_lock); break; default: return -EINVAL; diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h index 2b81e5b9ece39f5174366a913ab4035eb980ee37..6eae2b8d56fb891c5eb57835d6bef47511cabf87 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -174,7 +174,6 @@ struct fd_ctx { struct msm_fd_mem_pool mem_pool; struct msm_fd_stats *stats; struct msm_fd_buf_handle work_buf; - struct mutex lock; }; /* diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c index eab56b70e646f95c7ede7493092ee59910b22fcc..8f3cffb4c3dac10f48c8ed290d69f42b3eab01c2 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c @@ -86,7 +86,7 @@ struct msm_isp_bufq *msm_isp_get_bufq( /* bufq_handle cannot be 0 */ if ((bufq_handle == 0) || bufq_index >= BUF_MGR_NUM_BUF_Q || - (bufq_index >= buf_mgr->num_buf_q)) + (bufq_index > buf_mgr->num_buf_q)) return NULL; bufq = &buf_mgr->bufq[bufq_index]; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index b2d152bf4ef0fb0e0df850edc73aeb05d0163bbc..1f1435fe282e910d390847dbe532117f2d857cc0 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -786,7 +786,6 @@ struct vfe_device { size_t num_norm_clk; bool hvx_clk_state; enum cam_ahb_clk_vote ahb_vote; - enum cam_ahb_clk_vote user_requested_ahb_vote; struct cx_ipeak_client *vfe_cx_ipeak; /* Sync variables*/ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index 981832b5a586e651529556568dc860a12a3402ca..f5533fd9062ed13aff74c79eff6ade9a2fff3149 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -702,12 +702,6 @@ static void msm_vfe40_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { - if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { - pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); - spin_unlock_irqrestore(&vfe_dev->reg_update_lock, - flags); - return; - } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0] + 0x378); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c index cc4dd5eaf93e488ebd136a2bda6916200a10ccf9..c85bf1655b8c8070c0cd44fa4619a6e36c6b356f 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -560,12 +560,6 @@ static void msm_vfe44_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { - if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { - pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); - spin_unlock_irqrestore(&vfe_dev->reg_update_lock, - flags); - return; - } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0] + 0x378); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c index 632624034a04bd8502a26d156d2f528b116c1163..72ce32940c296fd6155ef3052b0bf00cadd1779d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c @@ -499,12 +499,6 @@ static void msm_vfe46_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { - if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { - pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); - spin_unlock_irqrestore(&vfe_dev->reg_update_lock, - flags); - return; - } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0] + 0x3D8); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 6716bb6caad64ca254a651a472c7bda02f9cfde0..6515e3d6ecbce445767fd5cc81270525b3e4ce67 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -274,12 +274,10 @@ int msm_isp47_ahb_clk_cfg(struct vfe_device *vfe_dev, enum cam_ahb_clk_vote src_clk_vote; struct msm_isp_clk_rates clk_rates; - if (ahb_cfg) { + if (ahb_cfg) vote = msm_isp47_get_cam_clk_vote(ahb_cfg->vote); - vfe_dev->user_requested_ahb_vote = vote; - } else { - vote = vfe_dev->user_requested_ahb_vote; - } + else + vote = CAM_AHB_SVS_VOTE; vfe_dev->hw_info->vfe_ops.platform_ops.get_clk_rates(vfe_dev, &clk_rates); @@ -329,7 +327,6 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev) if (rc) goto clk_enable_failed; - vfe_dev->user_requested_ahb_vote = CAM_AHB_SVS_VOTE; rc = cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SVS_VOTE); if (rc < 0) { pr_err("%s: failed to vote for AHB\n", __func__); @@ -735,12 +732,6 @@ void msm_vfe47_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { - if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { - pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); - spin_unlock_irqrestore(&vfe_dev->reg_update_lock, - flags); - return; - } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0] + 0x4AC); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index a9155b06e37f90d18c4d87a764e29301d208f8e6..333e11a8a0d77181a1d2f1a70244bea28443ad49 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -776,6 +781,40 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev, } } +static int msm_isp_check_sync_time(struct msm_vfe_src_info *src_info, + struct msm_isp_timestamp *ts, + struct master_slave_resource_info *ms_res) +{ + int i; + struct msm_vfe_src_info *master_src_info = NULL; + uint32_t master_time = 0, current_time; + + if (!ms_res->src_sof_mask) + return 0; + + for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) { + if (ms_res->src_info[i] == NULL) + continue; + if (src_info == ms_res->src_info[i] || + ms_res->src_info[i]->active == 0) + continue; + if (ms_res->src_sof_mask & + (1 << ms_res->src_info[i]->dual_hw_ms_info.index)) { + master_src_info = ms_res->src_info[i]; + break; + } + } + if (!master_src_info) + return 0; + master_time = master_src_info-> + dual_hw_ms_info.sof_info.mono_timestamp_ms; + current_time = ts->buf_time.tv_sec * 1000 + + ts->buf_time.tv_usec / 1000; + if ((current_time - master_time) > ms_res->sof_delta_threshold) + return 1; + return 0; +} + static void msm_isp_sync_dual_cam_frame_id( struct vfe_device *vfe_dev, struct master_slave_resource_info *ms_res, @@ -790,11 +829,24 @@ static void msm_isp_sync_dual_cam_frame_id( if (src_info->dual_hw_ms_info.sync_state == ms_res->dual_sync_mode) { - (frame_src == VFE_PIX_0) ? src_info->frame_id += + if (msm_isp_check_sync_time(src_info, ts, ms_res) == 0) { + (frame_src == VFE_PIX_0) ? src_info->frame_id += vfe_dev->axi_data.src_info[frame_src]. sof_counter_step : src_info->frame_id++; - return; + return; + } + ms_res->src_sof_mask = 0; + ms_res->active_src_mask = 0; + for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) { + if (ms_res->src_info[i] == NULL) + continue; + if (ms_res->src_info[i]->active == 0) + continue; + ms_res->src_info[i]->dual_hw_ms_info. + sync_state = + MSM_ISP_DUAL_CAM_ASYNC; + } } /* find highest frame id */ @@ -2444,12 +2496,6 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg) rc = -1; return rc; } - if (ab_ib_vote->num_src >= VFE_AXI_SRC_MAX) { - pr_err("%s: ab_ib_vote num_src is exceeding limit\n", - __func__); - rc = -1; - return rc; - } if (ab_ib_vote->lpm_mode) { for (i = 0; i < ab_ib_vote->num_src; i++) { stream_info = @@ -2575,7 +2621,6 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint32_t bufq_handle = 0, bufq_id = 0; struct msm_isp_timestamp timestamp; - struct msm_vfe_frame_request_queue *queue_req; unsigned long flags; int vfe_idx; @@ -2612,18 +2657,8 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, VFE_PING_FLAG); msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); - stream_info->undelivered_request_cnt = 0; spin_unlock_irqrestore(&stream_info->lock, flags); - while (!list_empty(&stream_info->request_q)) { - queue_req = list_first_entry_or_null( - &stream_info->request_q, - struct msm_vfe_frame_request_queue, list); - if (queue_req) { - queue_req->cmd_used = 0; - list_del(&queue_req->list); - } - } for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) { bufq_handle = stream_info->bufq_handle[bufq_id]; @@ -3263,6 +3298,10 @@ int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg) rc = msm_isp_start_axi_stream( vfe_dev, stream_cfg_cmd); +#if defined(CONFIG_SONY_CAM_V4L2) + pr_info("%s: msm_isp_start_axi_stream: rc %d\n", + __func__, rc); +#endif } else { rc = msm_isp_stop_axi_stream( vfe_dev, stream_cfg_cmd); @@ -3285,8 +3324,13 @@ int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg) } if (rc < 0) +#if defined(CONFIG_SONY_CAM_V4L2) + pr_err("%s: start/stop %d stream failed: rc %d\n", __func__, + stream_cfg_cmd->cmd, rc); +#else pr_err("%s: start/stop %d stream failed\n", __func__, stream_cfg_cmd->cmd); +#endif return rc; } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h index 0f029c0d517849a323a71c98ff3b1612ca45d995..a8d4cfb43927e98f825b5e4384ce5071269a04f4 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h @@ -136,7 +136,7 @@ static inline void msm_isp_cfg_stream_scratch( } static inline struct msm_vfe_axi_stream *msm_isp_get_stream_common_data( - struct vfe_device *vfe_dev, uint32_t stream_idx) + struct vfe_device *vfe_dev, int stream_idx) { struct msm_vfe_common_dev_data *common_data = vfe_dev->common_data; struct msm_vfe_axi_stream *stream_info; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 92b1f2ea871ba8a095d61a07803db42df162070c..e87f2414a8798b7c973ccae1e1080c5eae50a608 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -196,7 +196,7 @@ uint32_t msm_isp_get_framedrop_period( return 32; break; case SKIP_ALL: - return SKIP_ALL; + return 1; default: return 1; } diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 9c3bd7b41ce90007778940b221639fb735e8ddfc..045efb219a5ca9da20b08d25e71ae28610bbe543 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -1025,9 +1030,6 @@ static void msm_ispif_config_stereo(struct ispif_device *ispif, enum msm_ispif_vfe_intf vfe_intf; uint32_t stereo_3d_threshold = STEREO_DEFAULT_3D_THRESHOLD; - if (params->num > MAX_PARAM_ENTRIES) - return; - for (i = 0; i < params->num; i++) { vfe_intf = params->entries[i].vfe_intf; if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { @@ -1619,7 +1621,11 @@ static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out, ispif_process_irq(ispif, out, VFE0); } +#if defined(CONFIG_SONY_CAM_V4L2) + if (ispif->vfe_info.num_vfe > 1) { +#else if (ispif->hw_num_isps > 1) { +#endif if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) { if (atomic_dec_and_test(&ispif->reset_trig[VFE1])) complete(&ispif->reset_complete[VFE1]); @@ -1905,9 +1911,20 @@ static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd, { struct ispif_device *ispif = (struct ispif_device *)v4l2_get_subdevdata(sd); +#if defined(CONFIG_SONY_CAM_V4L2) + struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg; +#endif switch (cmd) { case VIDIOC_MSM_ISPIF_CFG: +#if defined(CONFIG_SONY_CAM_V4L2) + if (pcdata->cfg_type == ISPIF_RELEASE) { + ispif->ispif_sof_debug = 0; + ispif->ispif_rdi0_debug = 0; + ispif->ispif_rdi1_debug = 0; + ispif->ispif_rdi2_debug = 0; + } +#endif return msm_ispif_cmd(sd, arg); case VIDIOC_MSM_ISPIF_CFG_EXT: return msm_ispif_cmd_ext(sd, arg); @@ -2034,6 +2051,9 @@ static int ispif_probe(struct platform_device *pdev) if (rc) /* backward compatibility */ ispif->hw_num_isps = 1; +#if defined(CONFIG_SONY_CAM_V4L2) + ispif->vfe_info.num_vfe = ispif->hw_num_isps; +#endif /* not an error condition */ rc = 0; } diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c index 821833d539057f2388c41ecb9a74ac3195c294c4..e40869d41a5d057ee7d2b04ae022f8628b325d3d 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -903,45 +903,26 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, void msm_jpeg_io_dump(void *base, int size) { - char line_str[128]; + char line_str[128], *p_str; void __iomem *addr = (void __iomem *)base; int i; u32 *p = (u32 *) addr; - size_t offset = 0; - size_t used = 0; - size_t min_range = 0; - size_t sizeof_line_str = sizeof(line_str); u32 data; JPEG_DBG_HIGH("%s:%d] %pK %d", __func__, __LINE__, addr, size); line_str[0] = '\0'; + p_str = line_str; for (i = 0; i < size/4; i++) { if (i % 4 == 0) { - used = snprintf(line_str + offset, - sizeof_line_str - offset, "%pK ", p); - if ((used < min_range) || - (offset + used >= sizeof_line_str)) { - JPEG_PR_ERR("%s\n", line_str); - offset = 0; - line_str[0] = '\0'; - } else { - offset += used; - } + snprintf(p_str, 12, "%08lx: ", (unsigned long)p); + p_str += 10; } data = msm_camera_io_r(p++); - used = snprintf(line_str + offset, - sizeof_line_str - offset, "%08x ", data); - if ((used < min_range) || - (offset + used >= sizeof_line_str)) { - JPEG_PR_ERR("%s\n", line_str); - offset = 0; - line_str[0] = '\0'; - } else { - offset += used; - } + snprintf(p_str, 12, "%08x ", data); + p_str += 9; if ((i + 1) % 4 == 0) { JPEG_DBG_HIGH("%s\n", line_str); line_str[0] = '\0'; - offset = 0; + p_str = line_str; } } if (line_str[0] != '\0') diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c index d27f56a9ad658dc7d2eb6f1dc07795c30d74c9ff..8eebb2f49eeb9166003e1c471893174f20b434e8 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include @@ -827,7 +832,11 @@ int msm_jpeg_ioctl_hw_cmd(struct msm_jpeg_device *pgmn_dev, __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset, hw_cmd.mask, hw_cmd.data, (unsigned long) hw_cmd.pdata); +#if defined(CONFIG_SONY_CAM_V4L2) + if (is_copy_to_user > 0) { +#else if (is_copy_to_user >= 0) { +#endif if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) { JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); return -EFAULT; diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index 194a6583103e764df851a85bbbffa0d325fdc01c..9cb7d5299ef87ade6bfb5bb9b1d410f04d5bcb02 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -34,7 +34,6 @@ static struct v4l2_device *msm_v4l2_dev; static struct list_head ordered_sd_list; -static struct mutex ordered_sd_mtx; static struct pm_qos_request msm_v4l2_pm_qos_request; @@ -288,7 +287,6 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) return; while (1) { - unsigned long wl_flags; if (try_count > 5) { pr_err("%s : not able to delete stream %d\n", @@ -296,20 +294,18 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) break; } - write_lock_irqsave(&session->stream_rwlock, wl_flags); + write_lock(&session->stream_rwlock); try_count++; stream = msm_queue_find(&session->stream_q, struct msm_stream, list, __msm_queue_find_stream, &stream_id); if (!stream) { - write_unlock_irqrestore(&session->stream_rwlock, - wl_flags); + write_unlock(&session->stream_rwlock); return; } if (msm_vb2_get_stream_state(stream) != 1) { - write_unlock_irqrestore(&session->stream_rwlock, - wl_flags); + write_unlock(&session->stream_rwlock); continue; } @@ -319,7 +315,7 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) kfree(stream); stream = NULL; spin_unlock_irqrestore(&(session->stream_q.lock), flags); - write_unlock_irqrestore(&session->stream_rwlock, wl_flags); + write_unlock(&session->stream_rwlock); break; } @@ -389,11 +385,6 @@ static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev, struct msm_sd_subdev *temp_sd; list_for_each_entry(temp_sd, sd_list, list) { - if (temp_sd == msm_subdev) { - pr_err("%s :Fail to add the same sd %d\n", - __func__, __LINE__); - return; - } if (msm_subdev->close_seq < temp_sd->close_seq) { list_add_tail(&msm_subdev->list, &temp_sd->list); return; @@ -410,9 +401,7 @@ int msm_sd_register(struct msm_sd_subdev *msm_subdev) if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev)) return -EIO; - mutex_lock(&ordered_sd_mtx); msm_add_sd_in_position(msm_subdev, &ordered_sd_list); - mutex_unlock(&ordered_sd_mtx); return __msm_sd_register_subdev(&msm_subdev->sd); } EXPORT_SYMBOL(msm_sd_register); @@ -746,16 +735,6 @@ static long msm_private_ioctl(struct file *file, void *fh, if (!event_data) return -EINVAL; - switch (cmd) { - case MSM_CAM_V4L2_IOCTL_NOTIFY: - case MSM_CAM_V4L2_IOCTL_CMD_ACK: - case MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG: - case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR: - break; - default: - return -ENOTTY; - } - memset(&event, 0, sizeof(struct v4l2_event)); session_id = event_data->session_id; stream_id = event_data->stream_id; @@ -824,13 +803,11 @@ static long msm_private_ioctl(struct file *file, void *fh, __func__); } - mutex_lock(&ordered_sd_mtx); if (!list_empty(&msm_v4l2_dev->subdevs)) { list_for_each_entry(msm_sd, &ordered_sd_list, list) __msm_sd_notify_freeze_subdevs(msm_sd, event_data->status); } - mutex_unlock(&ordered_sd_mtx); } break; @@ -1015,11 +992,9 @@ static int msm_close(struct file *filep) struct msm_sd_subdev *msm_sd; /*stop all hardware blocks immediately*/ - mutex_lock(&ordered_sd_mtx); if (!list_empty(&msm_v4l2_dev->subdevs)) list_for_each_entry(msm_sd, &ordered_sd_list, list) __msm_sd_close_subdevs(msm_sd, &sd_close); - mutex_unlock(&ordered_sd_mtx); /* remove msm_v4l2_pm_qos_request */ msm_pm_qos_remove_request(); @@ -1375,7 +1350,6 @@ static int msm_probe(struct platform_device *pdev) msm_init_queue(msm_session_q); spin_lock_init(&msm_eventq_lock); spin_lock_init(&msm_pid_lock); - mutex_init(&ordered_sd_mtx); INIT_LIST_HEAD(&ordered_sd_list); cam_debugfs_root = debugfs_create_dir(MSM_CAM_LOGSYNC_FILE_BASEDIR, diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h index 8bdb14f5c16e9026c0bca5b503db8d967770aae6..dce47bc7249c033a57035bfad23c28a092ec00a1 100644 --- a/drivers/media/platform/msm/camera_v2/msm.h +++ b/drivers/media/platform/msm/camera_v2/msm.h @@ -46,7 +46,6 @@ extern bool is_daemon_status; struct msm_video_device { struct video_device *vdev; atomic_t opened; - struct mutex video_drvdata_mutex; }; struct msm_queue_head { diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c index e271c7fcd1b6b665dc80d96d5af728745aed50be..719b14226067a07ec6e3efa3b269f69154246913 100644 --- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c @@ -47,23 +47,22 @@ int msm_vb2_buf_init(struct vb2_buffer *vb) struct msm_session *session; struct msm_vb2_buffer *msm_vb2_buf; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - unsigned long rl_flags; session = msm_get_session_from_vb2q(vb->vb2_queue); if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s: Couldn't find stream\n", __func__); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } msm_vb2_buf = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); msm_vb2_buf->in_freeq = 0; - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return 0; } @@ -72,7 +71,7 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; - unsigned long flags, rl_flags; + unsigned long flags; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); @@ -85,19 +84,19 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) if (IS_ERR_OR_NULL(session)) return; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return; } spin_lock_irqsave(&stream->stream_lock, flags); list_add_tail(&msm_vb2->list, &stream->queued_list); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); } static void msm_vb2_buf_finish(struct vb2_buffer *vb) @@ -105,26 +104,26 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; - unsigned long flags, rl_flags; + unsigned long flags; struct msm_vb2_buffer *msm_vb2_entry, *temp; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); msm_vb2 = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); if (!msm_vb2) { pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__); - return; + return; } session = msm_get_session_from_vb2q(vb->vb2_queue); if (IS_ERR_OR_NULL(session)) return; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return; } @@ -137,7 +136,7 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) } } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return; } @@ -146,19 +145,19 @@ static void msm_vb2_stop_stream(struct vb2_queue *q) struct msm_vb2_buffer *msm_vb2, *temp; struct msm_stream *stream; struct msm_session *session; - unsigned long flags, rl_flags; + unsigned long flags; struct vb2_v4l2_buffer *vb2_v4l2_buf; session = msm_get_session_from_vb2q(q); if (IS_ERR_OR_NULL(session)) return; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream_from_vb2q(q); if (!stream) { pr_err_ratelimited("%s:%d] NULL stream", __func__, __LINE__); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return; } @@ -178,7 +177,7 @@ static void msm_vb2_stop_stream(struct vb2_queue *q) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); } int msm_vb2_get_stream_state(struct msm_stream *stream) @@ -256,17 +255,17 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, struct msm_session *session; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags, rl_flags; + unsigned long flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return NULL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return NULL; } @@ -292,7 +291,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return vb2_v4l2_buf; } @@ -303,18 +302,18 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, struct msm_session *session; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags, rl_flags; + unsigned long flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return NULL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return NULL; } @@ -338,7 +337,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return vb2_v4l2_buf; } @@ -350,17 +349,17 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, struct msm_vb2_buffer *msm_vb2; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; int rc = 0; - unsigned long flags, rl_flags; + unsigned long flags; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } @@ -375,8 +374,7 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, pr_err("VB buffer is INVALID vb=%pK, ses_id=%d, str_id=%d\n", vb, session_id, stream_id); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, - rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } msm_vb2 = @@ -393,7 +391,7 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return rc; } @@ -401,7 +399,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, unsigned int stream_id, uint32_t sequence, struct timeval *ts, uint32_t reserved) { - unsigned long flags, rl_flags; + unsigned long flags; struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; @@ -412,11 +410,11 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } @@ -431,8 +429,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, pr_err("VB buffer is INVALID ses_id=%d, str_id=%d, vb=%pK\n", session_id, stream_id, vb); spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, - rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } msm_vb2 = @@ -453,7 +450,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return rc; } @@ -464,18 +461,18 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, struct msm_session *session; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; struct msm_vb2_buffer *msm_vb2 = NULL; - unsigned long flags, rl_flags; + unsigned long flags; long rc = -EINVAL; session = msm_get_session(session_id); if (IS_ERR_OR_NULL(session)) return rc; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } @@ -504,14 +501,14 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, end: spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return rc; } EXPORT_SYMBOL(msm_vb2_return_buf_by_idx); static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) { - unsigned long flags, rl_flags; + unsigned long flags; struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct msm_session *session; @@ -521,11 +518,11 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) if (IS_ERR_OR_NULL(session)) return -EINVAL; - read_lock_irqsave(&session->stream_rwlock, rl_flags); + read_lock(&session->stream_rwlock); stream = msm_get_stream(session, stream_id); if (IS_ERR_OR_NULL(stream)) { - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return -EINVAL; } @@ -537,7 +534,7 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); - read_unlock_irqrestore(&session->stream_rwlock, rl_flags); + read_unlock(&session->stream_rwlock); return 0; } diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 25fc34b26bc1bb9c27445d7bbed29af48dd09d76..9979e896d7a97af4936f97b43df2877e8f7e7388 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "MSM-CPP %s:%d " fmt, __func__, __LINE__ @@ -124,6 +129,12 @@ static int msm_cpp_dump_addr(struct cpp_device *cpp_dev, struct msm_cpp_frame_info_t *frame_info); static int32_t msm_cpp_reset_vbif_and_load_fw(struct cpp_device *cpp_dev); +#if defined(CONFIG_SONY_CAM_V4L2) +#define CPP_DBG(fmt, args...) +#define CPP_LOW(fmt, args...) +#define ERR_USER_COPY(to) +#define ERR_COPY_FROM_USER() +#else #if CONFIG_MSM_CPP_DBG #define CPP_DBG(fmt, args...) pr_err(fmt, ##args) #else @@ -138,6 +149,7 @@ static int32_t msm_cpp_reset_vbif_and_load_fw(struct cpp_device *cpp_dev); #define ERR_USER_COPY(to) pr_err("copy %s user\n", \ ((to) ? "to" : "from")) #define ERR_COPY_FROM_USER() ERR_USER_COPY(0) +#endif #define msm_dequeue(queue, member, pop_dir) ({ \ unsigned long flags; \ @@ -304,7 +316,11 @@ static void cpp_timer_callback(unsigned long data); uint8_t induce_error; static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev); +#if defined(CONFIG_SONY_CAM_V4L2) +static inline void msm_cpp_write(u32 data, void __iomem *cpp_base) +#else static void msm_cpp_write(u32 data, void __iomem *cpp_base) +#endif { msm_camera_io_w((data), cpp_base + MSM_CPP_MICRO_FIFO_RX_DATA); } @@ -1086,6 +1102,14 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) goto reg_enable_failed; } +#if defined(CONFIG_SONY_CAM_V4L2) +/* TODO: Temporary fix for cpp poll command fail */ + rc = msm_cpp_set_micro_clk(cpp_dev); + if (rc < 0) { + pr_err("%s: reset micro clk failed\n", __func__); + goto clk_failed; + } +#else if (cpp_dev->micro_reset) { rc = msm_cpp_set_micro_clk(cpp_dev); if (rc < 0) { @@ -1093,6 +1117,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) goto clk_failed; } } +#endif rc = msm_camera_clk_enable(&cpp_dev->pdev->dev, cpp_dev->clk_info, cpp_dev->cpp_clk, cpp_dev->num_clks, true); diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile index b04560fe42bc07533ad8884f337d9aaaa6f3a87c..781fbf6d3f4ab60027941a8fe5b4ef7131b3a725 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/Makefile +++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile @@ -5,5 +5,5 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ eeprom/ ois/ flash/ ir_led/ ir_cut/ -obj-$(CONFIG_MSMB_CAMERA) += laser_led/ obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o +obj-$(CONFIG_SONY_CAM_V4L2) += sony_camera_v4l2.o diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index b1bea12c2cc3414440b31471deefde83873fc712..bc844bb87db5f230bba63c2816b8e9cdeb88ca5c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1707,10 +1707,6 @@ static long msm_actuator_subdev_do_ioctl( parg = &actuator_data; break; } - break; - case VIDIOC_MSM_ACTUATOR_CFG: - pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd); - return -EINVAL; } rc = msm_actuator_subdev_ioctl(sd, cmd, parg); diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c index f2c765a4649f5497cdc4d71ffb1a436020cf2d54..f5c321d7f328bbfdb93033562ff9256413cdaaaf 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c +++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -331,9 +336,6 @@ static int32_t msm_cci_addr_to_num_bytes( case MSM_CAMERA_I2C_3B_ADDR: retVal = 3; break; - case MSM_CAMERA_I2C_DWORD_ADDR: - retVal = 4; - break; default: pr_err("%s: %d failed: %d\n", __func__, __LINE__, addr_type); retVal = 1; @@ -406,10 +408,6 @@ static int32_t msm_cci_calc_cmd_len(struct cci_device *cci_dev, if (cmd->reg_addr + 1 == (cmd+1)->reg_addr) { len += data_len; - if (len > cci_dev->payload_size) { - len = len - data_len; - break; - } *pack += data_len; } else break; @@ -471,6 +469,7 @@ static int32_t msm_cci_wait_report_cmd(struct cci_device *cci_dev, return msm_cci_wait(cci_dev, master, queue); } +#if !defined(CONFIG_SONY_CAM_V4L2) static void msm_cci_process_half_q(struct cci_device *cci_dev, enum cci_i2c_master_t master, enum cci_i2c_queue_t queue) @@ -489,6 +488,7 @@ static void msm_cci_process_half_q(struct cci_device *cci_dev, spin_unlock_irqrestore(&cci_dev->cci_master_info[master]. lock_q[queue], flags); } +#endif static int32_t msm_cci_process_full_q(struct cci_device *cci_dev, enum cci_i2c_master_t master, @@ -709,7 +709,9 @@ static int32_t msm_cci_data_queue(struct cci_device *cci_dev, } continue; } +#if !defined(CONFIG_SONY_CAM_V4L2) msm_cci_process_half_q(cci_dev, master, queue); +#endif } CDBG("%s cmd_size %d addr 0x%x data 0x%x\n", __func__, diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index 8d091320cbca459d6e1076bf544530c7ed3bbfda..d50bf85c92821cec129ea1e405271df290957b09 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -584,7 +589,9 @@ static int msm_csiphy_2phase_lane_config_v50( uint32_t lane_enable = 0, mask = 1; uint16_t lane_mask = 0, i = 0, offset; void __iomem *csiphybase; - +/* SONY_BEGIN (Change to internal bias) */ + uint32_t tmp = 0; +/* SONY_END (Change to internal bias) */ csiphybase = csiphy_dev->base; lane_mask = csiphy_params->lane_mask & 0x1f; @@ -733,6 +740,28 @@ static int msm_csiphy_2phase_lane_config_v50( mask <<= 1; } } +/* SONY_BEGIN (Change to internal bias) */ + /* 0x0CA34024 */ + tmp = msm_camera_io_r(csiphybase + 0x24); + tmp |= 0x04; + msm_camera_io_w(tmp, csiphybase + 0x24); + /* 0x0CA34224 */ + tmp = msm_camera_io_r(csiphybase + 0x224); + tmp |= 0x04; + msm_camera_io_w(tmp, csiphybase + 0x224); + /* 0x0CA34424 */ + tmp = msm_camera_io_r(csiphybase + 0x424); + tmp |= 0x04; + msm_camera_io_w(tmp, csiphybase + 0x424); + /* 0x0CA34624 */ + tmp = msm_camera_io_r(csiphybase + 0x624); + tmp |= 0x04; + msm_camera_io_w(tmp, csiphybase + 0x624); + /* 0x0CA34724 */ + tmp = msm_camera_io_r(csiphybase + 0x724); + tmp |= 0x04; + msm_camera_io_w(tmp, csiphybase + 0x724); +/* SONY_END (Change to internal bias) */ msm_csiphy_cphy_irq_config(csiphy_dev, csiphy_params); return 0; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index c77367ed1603d705808340906d515ac2cd5312b1..cf7d1a8aa1f48519cb3265ea57f71ea0f19dfd30 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -508,42 +508,18 @@ static int32_t msm_flash_init( return 0; } +#ifdef CONFIG_COMPAT static int32_t msm_flash_init_prepare( struct msm_flash_ctrl_t *flash_ctrl, struct msm_flash_cfg_data_t *flash_data) { -#ifdef CONFIG_COMPAT - struct msm_flash_cfg_data_t flash_data_k; - struct msm_flash_init_info_t flash_init_info; - int32_t i = 0; - - if (!is_compat_task()) { - /*for 64-bit usecase,it need copy the data to local memory*/ - flash_data_k.cfg_type = flash_data->cfg_type; - for (i = 0; i < MAX_LED_TRIGGERS; i++) { - flash_data_k.flash_current[i] = - flash_data->flash_current[i]; - flash_data_k.flash_duration[i] = - flash_data->flash_duration[i]; - } - - flash_data_k.cfg.flash_init_info = &flash_init_info; - if (copy_from_user(&flash_init_info, - (void __user *)(flash_data->cfg.flash_init_info), - sizeof(struct msm_flash_init_info_t))) { - pr_err("%s copy_from_user failed %d\n", - __func__, __LINE__); - return -EFAULT; - } - return msm_flash_init(flash_ctrl, &flash_data_k); - } - /* - * for 32-bit usecase,it already copy the userspace - * data to local memory in msm_flash_subdev_do_ioctl() - * so here do not need copy from user - */ return msm_flash_init(flash_ctrl, flash_data); +} #else +static int32_t msm_flash_init_prepare( + struct msm_flash_ctrl_t *flash_ctrl, + struct msm_flash_cfg_data_t *flash_data) +{ struct msm_flash_cfg_data_t flash_data_k; struct msm_flash_init_info_t flash_init_info; int32_t i = 0; @@ -558,15 +534,15 @@ static int32_t msm_flash_init_prepare( flash_data_k.cfg.flash_init_info = &flash_init_info; if (copy_from_user(&flash_init_info, - (void __user *)(flash_data->cfg.flash_init_info), + (void *)(flash_data->cfg.flash_init_info), sizeof(struct msm_flash_init_info_t))) { pr_err("%s copy_from_user failed %d\n", __func__, __LINE__); return -EFAULT; } return msm_flash_init(flash_ctrl, &flash_data_k); -#endif } +#endif static int32_t msm_flash_prepare( struct msm_flash_ctrl_t *flash_ctrl) @@ -1213,9 +1189,6 @@ static long msm_flash_subdev_do_ioctl( break; } break; - case VIDIOC_MSM_FLASH_CFG: - pr_err("invalid cmd 0x%x received\n", cmd); - return -EINVAL; default: return msm_flash_subdev_ioctl(sd, cmd, arg); } diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c index fc6ceb1b590faac0da71f33a593d6abad5dda73b..1a40aa1c78bdfdad09e02863627cb4ed44da05f1 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2016, 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 @@ -17,15 +17,13 @@ #undef CDBG #define CDBG(fmt, args...) pr_debug(fmt, ##args) #define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) -#define MAX_I2C_ADDR_TYPE_SIZE (MSM_CAMERA_I2C_3B_ADDR + 1) -#define MAX_I2C_DATA_TYPE_SIZE (MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA + 1) int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, uint32_t addr, uint16_t *data, enum msm_camera_i2c_data_type data_type) { int32_t rc = -EFAULT; - unsigned char buf[MAX_I2C_ADDR_TYPE_SIZE + MAX_I2C_DATA_TYPE_SIZE]; + unsigned char buf[client->addr_type+data_type]; struct msm_camera_cci_ctrl cci_ctrl; if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR @@ -67,8 +65,7 @@ int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR - && client->addr_type != MSM_CAMERA_I2C_3B_ADDR - && client->addr_type != MSM_CAMERA_I2C_DWORD_ADDR) + && client->addr_type != MSM_CAMERA_I2C_3B_ADDR) || num_byte == 0) return rc; diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c index 2c31fb22c121869a98dba6aa2cacdb28dd55bb95..5d3c7d65bd8f03c5ccc375dced1de687c0906f36 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "msm_camera_dt_util.h" #include "msm_camera_io_util.h" @@ -575,8 +580,6 @@ int msm_camera_get_dt_power_setting_data(struct device_node *of_node, ps[i].seq_val = SENSOR_GPIO_CUSTOM1; else if (!strcmp(seq_name, "sensor_gpio_custom2")) ps[i].seq_val = SENSOR_GPIO_CUSTOM2; - else if (!strcmp(seq_name, "sensor_gpio_custom3")) - ps[i].seq_val = SENSOR_GPIO_CUSTOM3; else rc = -EILSEQ; break; @@ -769,6 +772,92 @@ ERROR1: return rc; } +#if defined(CONFIG_SONY_CAM_V4L2) +int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size) +{ + int rc = 0, i = 0; + uint32_t count = 0; + uint32_t *val_array = NULL; + + if (!of_get_property(of_node, "qcom,gpio-set-tbl-num", &count)) + return 0; + + count /= sizeof(uint32_t); + if (!count) { + pr_err("%s qcom,gpio-set-tbl-num 0\n", __func__); + return 0; + } + + val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + gconf->cam_gpio_set_tbl = kzalloc(sizeof(struct msm_gpio_set_tbl) * + count, GFP_KERNEL); + if (!gconf->cam_gpio_set_tbl) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + gconf->cam_gpio_set_tbl_size = count; + + rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-num", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + if (val_array[i] >= gpio_array_size) { + pr_err("%s gpio set tbl index %d invalid\n", + __func__, val_array[i]); + return -EINVAL; + } + gconf->cam_gpio_set_tbl[i].gpio = gpio_array[val_array[i]]; + CDBG("%s cam_gpio_set_tbl[%d].gpio = %d\n", __func__, i, + gconf->cam_gpio_set_tbl[i].gpio); + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-flags", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + gconf->cam_gpio_set_tbl[i].flags = val_array[i]; + CDBG("%s cam_gpio_set_tbl[%d].flags = %ld\n", __func__, i, + gconf->cam_gpio_set_tbl[i].flags); + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-delay", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + gconf->cam_gpio_set_tbl[i].delay = val_array[i]; + CDBG("%s cam_gpio_set_tbl[%d].delay = %d\n", __func__, i, + gconf->cam_gpio_set_tbl[i].delay); + } + + kfree(val_array); + return rc; + +ERROR2: + kfree(gconf->cam_gpio_set_tbl); +ERROR1: + kfree(val_array); + gconf->cam_gpio_set_tbl_size = 0; + return rc; +} +#endif + int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, uint16_t gpio_array_size) @@ -1080,27 +1169,6 @@ int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, rc = 0; } - rc = of_property_read_u32(of_node, "qcom,gpio-custom3", &val); - if (rc != -EINVAL) { - if (rc < 0) { - pr_err("%s:%d read qcom,gpio-custom3 failed rc %d\n", - __func__, __LINE__, rc); - goto ERROR; - } else if (val >= gpio_array_size) { - pr_err("%s:%d qcom,gpio-custom3 invalid %d\n", - __func__, __LINE__, val); - rc = -EINVAL; - goto ERROR; - } - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM3] = - gpio_array[val]; - gconf->gpio_num_info->valid[SENSOR_GPIO_CUSTOM3] = 1; - CDBG("%s qcom,gpio-custom3 %d\n", __func__, - gconf->gpio_num_info->gpio_num[SENSOR_GPIO_CUSTOM3]); - } else { - rc = 0; - } - return rc; ERROR: @@ -1464,7 +1532,7 @@ int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, switch (power_setting->seq_type) { case SENSOR_CLK: if (power_setting->seq_val >= ctrl->clk_info_size) { - pr_err_ratelimited("%s clk index %d >= max %zu\n", __func__, + pr_err("%s clk index %d >= max %zu\n", __func__, power_setting->seq_val, ctrl->clk_info_size); goto power_up_failed; @@ -1476,7 +1544,7 @@ int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, ctrl->clk_info, ctrl->clk_ptr, ctrl->clk_info_size, true); if (rc < 0) { - pr_err_ratelimited("%s: clk enable failed\n", __func__); + pr_err("%s: clk enable failed\n", __func__); goto power_up_failed; } break; @@ -1559,7 +1627,7 @@ int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, CDBG("%s exit\n", __func__); return 0; power_up_failed: - pr_err_ratelimited("%s:%d failed\n", __func__, __LINE__); + pr_err("%s:%d failed\n", __func__, __LINE__); for (index--; index >= 0; index--) { CDBG("%s index %d\n", __func__, index); power_setting = &ctrl->power_setting[index]; diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h index 220915511cce470377b8e96baebf0ab82b48ae27..992b137da3676e30bd5db1ea7e32fcc3051eba7e 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef MSM_CAMERA_DT_UTIL_H__ #define MSM_CAMERA_DT_UTIL_H__ @@ -40,6 +45,12 @@ int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, uint16_t gpio_array_size); +#if defined(CONFIG_SONY_CAM_V4L2) +int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); +#endif + int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, uint16_t gpio_array_size); diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c index fcef053740989eee97e937cbf6853f380f002cb7..6fe1d27426b59a0b0b50e28c68448d7e5b846f33 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c @@ -9,6 +9,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ +#if defined(CONFIG_SONY_CAM_V4L2) +#include +#endif #include "msm_sensor.h" #include "msm_sd.h" #include "camera.h" @@ -23,6 +31,9 @@ static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl; static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl; +#if defined(CONFIG_SONY_CAM_V4L2) +static struct v4l2_file_operations msm_sensor_v4l2_subdev_fops; +#endif static void msm_sensor_adjust_mclk(struct msm_camera_power_ctrl_t *ctrl) { @@ -44,6 +55,343 @@ static void msm_sensor_adjust_mclk(struct msm_camera_power_ctrl_t *ctrl) return; } +#if defined(CONFIG_SONY_CAM_V4L2) +static int32_t msm_camera_get_power_settimgs_from_sensor_lib( + struct msm_camera_power_ctrl_t *power_info, + struct msm_sensor_power_setting_array *power_setting_array) +{ + int32_t rc = 0; + uint32_t size; + struct msm_sensor_power_setting *ps; + bool need_reverse = 0; + + if ((NULL == power_info->power_setting) || + (0 == power_info->power_setting_size)) { + + ps = power_setting_array->power_setting; + size = power_setting_array->size; + if ((NULL == ps) || (0 == size)) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -EINVAL; + goto FAILED_1; + } + + power_info->power_setting = + kzalloc(sizeof(*ps) * size, GFP_KERNEL); + if (!power_info->power_setting) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto FAILED_1; + } + memcpy(power_info->power_setting, + power_setting_array->power_setting, + sizeof(*ps) * size); + power_info->power_setting_size = size; + } + + ps = power_setting_array->power_down_setting; + size = power_setting_array->size_down; + if (NULL == ps || 0 == size) { + ps = power_info->power_setting; + size = power_info->power_setting_size; + need_reverse = 1; + } + + power_info->power_down_setting = + kzalloc(sizeof(*ps) * size, GFP_KERNEL); + if (!power_info->power_down_setting) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_UP; + } + memcpy(power_info->power_down_setting, + ps, + sizeof(*ps) * size); + power_info->power_down_setting_size = size; + + if (need_reverse) { + int c, end = size - 1; + struct msm_sensor_power_setting power_down_setting_t; + for (c = 0; c < size/2; c++) { + power_down_setting_t = + power_info->power_down_setting[c]; + power_info->power_down_setting[c] = + power_info->power_down_setting[end]; + power_info->power_down_setting[end] = + power_down_setting_t; + end--; + } + } + + return 0; +FREE_UP: + kfree(power_info->power_setting); +FAILED_1: + return rc; +} + +static int32_t msm_sensor_get_dt_data(struct device_node *of_node, + struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0, i = 0, ret = 0; + struct msm_camera_gpio_conf *gconf = NULL; + struct msm_camera_sensor_board_info *sensordata = NULL; + uint16_t *gpio_array = NULL; + uint16_t gpio_array_size = 0; + uint32_t id_info[MSM_SENSOR_NUM_ID_INFO_DATA]; + uint32_t count; + const uint32_t *p; + struct msm_camera_slave_info *slave_info; + + s_ctrl->sensordata = kzalloc(sizeof( + struct msm_camera_sensor_board_info), + GFP_KERNEL); + if (!s_ctrl->sensordata) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + sensordata = s_ctrl->sensordata; + + rc = of_property_read_string(of_node, "qcom,sensor-name", + &sensordata->sensor_name); + CDBG("%s qcom,sensor-name %s, rc %d\n", __func__, + sensordata->sensor_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SENSORDATA; + } + + rc = of_property_read_u32(of_node, "qcom,cci-master", + &s_ctrl->cci_i2c_master); + CDBG("%s qcom,cci-master %d, rc %d\n", __func__, s_ctrl->cci_i2c_master, + rc); + if (rc < 0) { + /* Set default master 0 */ + s_ctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SENSORDATA; + } + + /* Get sensor mount angle */ + if (0 > of_property_read_u32(of_node, "qcom,mount-angle", + &sensordata->sensor_info->sensor_mount_angle)) { + /* Invalidate mount angle flag */ + CDBG("%s:%d Default sensor mount angle\n", + __func__, __LINE__); + sensordata->sensor_info->is_mount_angle_valid = 0; + sensordata->sensor_info->sensor_mount_angle = 0; + } else { + sensordata->sensor_info->is_mount_angle_valid = 1; + } + CDBG("%s qcom,mount-angle %d\n", __func__, + sensordata->sensor_info->sensor_mount_angle); + if (0 > of_property_read_u32(of_node, "qcom,sensor-position", + &sensordata->sensor_info->position)) { + CDBG("%s:%d Default sensor position\n", __func__, __LINE__); + sensordata->sensor_info->position = 0; + } + CDBG("%s qcom,sensor-position %d\n", __func__, + sensordata->sensor_info->position); + if (0 > of_property_read_u32(of_node, "qcom,sensor-mode", + &sensordata->sensor_info->modes_supported)) { + CDBG("%s:%d Default sensor mode\n", __func__, __LINE__); + sensordata->sensor_info->modes_supported = 0; + } + CDBG("%s qcom,sensor-mode %d\n", __func__, + sensordata->sensor_info->modes_supported); + + s_ctrl->set_mclk_23880000 = of_property_read_bool(of_node, + "qcom,mclk-23880000"); + + CDBG("%s qcom,mclk-23880000 %d\n", __func__, + s_ctrl->set_mclk_23880000); + + rc = msm_sensor_get_dt_csi_data(of_node, &sensordata->csi_lane_params); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SENSOR_INFO; + } + + /*Get clocks information*/ + rc = msm_camera_get_clk_info(s_ctrl->pdev, + &s_ctrl->sensordata->power_info.clk_info, + &s_ctrl->sensordata->power_info.clk_ptr, + &s_ctrl->sensordata->power_info.clk_info_size); + if (rc < 0) { + pr_err("failed: msm_camera_get_clk_info rc %d", rc); + goto FREE_CSI; + } + + rc = msm_camera_get_dt_vreg_data(of_node, + &sensordata->power_info.cam_vreg, + &sensordata->power_info.num_vreg); + if (rc < 0) + goto FREE_CLK_DATA; + + rc = msm_camera_get_dt_power_setting_data(of_node, + sensordata->power_info.cam_vreg, + sensordata->power_info.num_vreg, + &sensordata->power_info); + + + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_VREG; + } + + + rc = msm_camera_get_power_settimgs_from_sensor_lib( + &sensordata->power_info, + &s_ctrl->power_setting_array); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_VREG; + } + + sensordata->power_info.gpio_conf = kzalloc( + sizeof(struct msm_camera_gpio_conf), GFP_KERNEL); + if (!sensordata->power_info.gpio_conf) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto FREE_PS; + } + gconf = sensordata->power_info.gpio_conf; + + gpio_array_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size) { + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, + GFP_KERNEL); + if (!gpio_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_CONF; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_CONF; + } + + rc = msm_camera_get_dt_gpio_set_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_REQ_TBL; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_SET_TBL; + } + } + rc = msm_sensor_get_dt_actuator_data(of_node, + &sensordata->actuator_info); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_PIN_TBL; + } + + sensordata->slave_info = kzalloc(sizeof(struct msm_camera_slave_info), + GFP_KERNEL); + if (!sensordata->slave_info) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto FREE_ACTUATOR_INFO; + } + + slave_info = sensordata->slave_info; + + p = of_get_property(of_node, "qcom,slave-id", &count); + if (!p || !count) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SLAVE_INFO; + } + + count /= sizeof(uint32_t); + + if (count > MSM_SENSOR_NUM_ID_INFO_DATA) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SLAVE_INFO; + } + + memset(id_info, 0, sizeof(*id_info)*MSM_SENSOR_NUM_ID_INFO_DATA); + + rc = of_property_read_u32_array(of_node, "qcom,slave-id", + id_info, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SLAVE_INFO; + } + + slave_info->sensor_slave_addr = id_info[MSM_SENSOR_SLAVEADDR_DATA]; + slave_info->sensor_id_reg_addr = id_info[MSM_SENSOR_IDREGADDR_DATA]; + slave_info->sensor_id = id_info[MSM_SENSOR_SENSOR_ID_DATA]; + slave_info->sensor_id_mask = id_info[MSM_SENSOR_SENIDMASK_DATA]; + CDBG("%s:%d slave addr 0x%x sensor reg 0x%x id 0x%x mask 0x%x\n", + __func__, __LINE__, + slave_info->sensor_slave_addr, + slave_info->sensor_id_reg_addr, + slave_info->sensor_id, + slave_info->sensor_id_mask); + + /*Optional property, don't return error if absent */ + ret = of_property_read_string(of_node, "qcom,vdd-cx-name", + &sensordata->misc_regulator); + CDBG("%s qcom,misc_regulator %s, rc %d\n", __func__, + sensordata->misc_regulator, ret); + + kfree(gpio_array); + + return rc; + +FREE_SLAVE_INFO: + kfree(s_ctrl->sensordata->slave_info); +FREE_ACTUATOR_INFO: + kfree(s_ctrl->sensordata->actuator_info); +FREE_GPIO_PIN_TBL: + kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); +FREE_GPIO_SET_TBL: + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl); +FREE_GPIO_REQ_TBL: + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); +FREE_GPIO_CONF: + kfree(s_ctrl->sensordata->power_info.gpio_conf); +FREE_PS: + kfree(s_ctrl->sensordata->power_info.power_setting); + kfree(s_ctrl->sensordata->power_info.power_down_setting); +FREE_VREG: + kfree(s_ctrl->sensordata->power_info.cam_vreg); +FREE_CLK_DATA: + msm_camera_put_clk_info(s_ctrl->pdev, + &s_ctrl->sensordata->power_info.clk_info, + &s_ctrl->sensordata->power_info.clk_ptr, + s_ctrl->sensordata->power_info.clk_info_size); +FREE_CSI: + kfree(s_ctrl->sensordata->csi_lane_params); +FREE_SENSOR_INFO: + kfree(s_ctrl->sensordata->sensor_info); +FREE_SENSORDATA: + kfree(s_ctrl->sensordata); + kfree(gpio_array); + return rc; +} +#endif + static void msm_sensor_misc_regulator( struct msm_sensor_ctrl_t *sctrl, uint32_t enable) { @@ -87,6 +435,9 @@ int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl) kfree(s_ctrl->sensordata->cam_slave_info); kfree(s_ctrl->sensordata->actuator_info); kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); +#if defined(CONFIG_SONY_CAM_V4L2) + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl); +#endif kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); kfree(s_ctrl->sensordata->power_info.gpio_conf); kfree(s_ctrl->sensordata->power_info.cam_vreg); @@ -354,6 +705,7 @@ static long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd, case MSM_SD_UNNOTIFY_FREEZE: return 0; default: + pr_err("%s cmd = %d\n", __func__, cmd); return -ENOIOCTLCMD; } } @@ -365,6 +717,23 @@ static long msm_sensor_subdev_do_ioctl( struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); switch (cmd) { +#if defined(CONFIG_SONY_CAM_V4L2) + case VIDIOC_DQEVENT: { + struct v4l2_fh *vfh = file->private_data; + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return -ENOIOCTLCMD; + return v4l2_event_dequeue(vfh, arg, + file->f_flags & O_NONBLOCK); + } + case VIDIOC_SUBSCRIBE_EVENT: { + struct v4l2_fh *vfh = file->private_data; + return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + } + case VIDIOC_UNSUBSCRIBE_EVENT: { + struct v4l2_fh *vfh = file->private_data; + return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + } +#endif case VIDIOC_MSM_SENSOR_CFG32: cmd = VIDIOC_MSM_SENSOR_CFG; default: @@ -372,13 +741,42 @@ static long msm_sensor_subdev_do_ioctl( } } +#if defined(CONFIG_SONY_CAM_V4L2) +static int msm_sensor_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); + int rc = v4l2_event_subscribe(fh, sub, 100, NULL); + if (rc != 0) { + pr_err("%s: Subs event_type =0x%x failed\n", __func__, sub->type); + } + if (s_ctrl) + s_ctrl->sof_count = 0; + return rc; +} + +static int msm_sensor_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + int rc = v4l2_event_unsubscribe(fh, sub); + if (rc != 0) { + pr_err("%s: Subs event_type =0x%x failed\n", __func__, sub->type); + } + return rc; +} +#endif + long msm_sensor_subdev_fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return video_usercopy(file, cmd, arg, msm_sensor_subdev_do_ioctl); } +#if defined(CONFIG_SONY_CAM_V4L2) +int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl, +#else static int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl, +#endif void __user *argp) { struct sensorb_cfg_data32 *cdata = (struct sensorb_cfg_data32 *)argp; @@ -584,12 +982,22 @@ static int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl, pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__); break; } +#if defined(CONFIG_SONY_CAM_V4L2) + read_config.data = local_data; + if (copy_to_user(read_config_ptr, &read_config, + sizeof(read_config))) { + pr_err("%s:%d copy failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } +#else if (copy_to_user(&read_config_ptr->data, &local_data, sizeof(local_data))) { pr_err("%s:%d failed\n", __func__, __LINE__); rc = -EFAULT; break; } +#endif break; } case CFG_SLAVE_WRITE_I2C_ARRAY: { @@ -700,6 +1108,96 @@ static int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl, kfree(reg_setting); break; } +#if defined(CONFIG_SONY_CAM_V4L2) + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting32 conf_array32; + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + uint16_t orig_sid = 0; + uint16_t orig_addr_type = 0; + + if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, s_ctrl->sensor_state); + rc = -EFAULT; + break; + } + + if (copy_from_user(&conf_array32, + (void *)compat_ptr(cdata->cfg.setting), + sizeof(struct msm_camera_i2c_seq_reg_setting32))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + conf_array.addr_type = conf_array32.addr_type; + conf_array.delay = conf_array32.delay; + conf_array.size = conf_array32.size; + conf_array.slave_addr = conf_array32.slave_addr; + conf_array.reg_setting = compat_ptr(conf_array32.reg_setting); + + if (!conf_array.size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, + (void *)(conf_array.reg_setting), + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + if (s_ctrl->sensor_i2c_client->cci_client) { + orig_sid = s_ctrl->sensor_i2c_client->cci_client->sid; + s_ctrl->sensor_i2c_client->cci_client->sid = + conf_array.slave_addr; + } else if (s_ctrl->sensor_i2c_client->client) { + orig_sid = s_ctrl->sensor_i2c_client->client->addr; + s_ctrl->sensor_i2c_client->client->addr = + conf_array.slave_addr; + } else { + pr_err("%s: error: no i2c/cci client found.", __func__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + if (conf_array.addr_type < MSM_CAMERA_I2C_ADDR_TYPE_MAX) { + orig_addr_type = s_ctrl->sensor_i2c_client->addr_type; + s_ctrl->sensor_i2c_client->addr_type = + conf_array.addr_type; + } else { + pr_err("%s: error: address type failed.", __func__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + if (s_ctrl->sensor_i2c_client->cci_client) + s_ctrl->sensor_i2c_client->cci_client->sid = orig_sid; + else + s_ctrl->sensor_i2c_client->client->addr = orig_sid; + s_ctrl->sensor_i2c_client->addr_type = orig_addr_type; + kfree(reg_setting); + break; + } +#else case CFG_WRITE_I2C_SEQ_ARRAY: { struct msm_camera_i2c_seq_reg_setting32 conf_array32; struct msm_camera_i2c_seq_reg_setting conf_array; @@ -759,7 +1257,7 @@ static int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl, kfree(reg_setting); break; } - +#endif case CFG_POWER_UP: if (s_ctrl->is_csid_tg_mode) goto DONE; @@ -1426,6 +1924,12 @@ static int msm_sensor_power(struct v4l2_subdev *sd, int on) static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = { .ioctl = msm_sensor_subdev_ioctl, .s_power = msm_sensor_power, +#ifdef CONFIG_COMPAT +#if defined(CONFIG_SONY_CAM_V4L2) + .subscribe_event = msm_sensor_subscribe_event, + .unsubscribe_event = msm_sensor_unsubscribe_event, +#endif +#endif }; static struct v4l2_subdev_ops msm_sensor_subdev_ops = { .core = &msm_sensor_subdev_core_ops, @@ -1486,6 +1990,100 @@ static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl = { .i2c_write_table_sync_block = msm_camera_tz_i2c_write_table_sync_block, }; +#if defined(CONFIG_SONY_CAM_V4L2) +int32_t msm_sensor_platform_probe(struct platform_device *pdev, + const void *data) +{ + int rc = 0; + struct msm_sensor_ctrl_t *s_ctrl = + (struct msm_sensor_ctrl_t *)data; + struct msm_camera_cci_client *cci_client = NULL; + uint32_t session_id; + unsigned long mount_pos = 0; + s_ctrl->pdev = pdev; + CDBG("%s called data %p\n", __func__, data); + CDBG("%s pdev name %s\n", __func__, pdev->id_entry->name); + if (pdev->dev.of_node) { + rc = msm_sensor_get_dt_data(pdev->dev.of_node, s_ctrl); + if (rc < 0) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + } + s_ctrl->sensordata->power_info.dev = &pdev->dev; + s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE; + s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!s_ctrl->sensor_i2c_client->cci_client) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + /* TODO: get CCI subdev */ + cci_client = s_ctrl->sensor_i2c_client->cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; + cci_client->sid = + s_ctrl->sensordata->slave_info->sensor_slave_addr >> 1; + cci_client->cid = 0; + cci_client->retries = 3; + cci_client->id_map = 0; + if (!s_ctrl->func_tbl) + s_ctrl->func_tbl = &msm_sensor_func_tbl; + if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_cci_func_tbl; + if (!s_ctrl->sensor_v4l2_subdev_ops) + s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + if (rc < 0) { + pr_err("%s %s power up failed\n", __func__, + s_ctrl->sensordata->sensor_name); + kfree(cci_client); + return rc; + } + + pr_info("%s %s probe succeeded\n", __func__, + s_ctrl->sensordata->sensor_name); + v4l2_subdev_init(&s_ctrl->msm_sd.sd, + s_ctrl->sensor_v4l2_subdev_ops); + snprintf(s_ctrl->msm_sd.sd.name, + sizeof(s_ctrl->msm_sd.sd.name), "%s", + s_ctrl->sensordata->sensor_name); + v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, pdev); + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); + s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; + s_ctrl->msm_sd.sd.entity.name = + s_ctrl->msm_sd.sd.name; + + mount_pos = s_ctrl->sensordata->sensor_info->position << 16; + mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> + sensor_mount_angle / 90) << 8); + s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; + + rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id); + CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); + s_ctrl->sensordata->sensor_info->session_id = session_id; + s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; + msm_sd_register(&s_ctrl->msm_sd); + msm_sensor_v4l2_subdev_fops = v4l2_subdev_fops; +#ifdef CONFIG_COMPAT + msm_sensor_v4l2_subdev_fops.compat_ioctl32 = + msm_sensor_subdev_fops_ioctl; +#endif + s_ctrl->msm_sd.sd.devnode->fops = + &msm_sensor_v4l2_subdev_fops; + + CDBG("%s:%d\n", __func__, __LINE__); + + s_ctrl->func_tbl->sensor_power_down(s_ctrl); + CDBG("%s:%d\n", __func__, __LINE__); + return rc; +} +#endif + int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) { struct msm_camera_cci_client *cci_client = NULL; diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h index 8f55f453bf0363d23c4a02fea05e211f6b7807fa..23e0aaebb18e8fc71f21074786981f0fc20bff2b 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef MSM_SENSOR_H #define MSM_SENSOR_H @@ -90,10 +95,19 @@ struct msm_sensor_ctrl_t { uint8_t is_csid_tg_mode; uint32_t is_secure; uint8_t bypass_video_node_creation; +#if defined(CONFIG_SONY_CAM_V4L2) + uint32_t sof_count; +#endif }; int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp); +#if defined(CONFIG_SONY_CAM_V4L2) +#ifdef CONFIG_COMPAT +int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp); +#endif +#endif + int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl); int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl); @@ -102,6 +116,11 @@ int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl); int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl); +#if defined(CONFIG_SONY_CAM_V4L2) +int32_t msm_sensor_platform_probe(struct platform_device *pdev, + const void *data); +#endif + int msm_sensor_update_cfg(struct msm_sensor_ctrl_t *s_ctrl); int msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl); diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 167ed549208808eaa87dcac0385a59964c65c493..a41d7dba490e0c8c243353259b52b2755e52bf4c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -108,11 +108,7 @@ static int32_t msm_sensor_driver_create_i2c_v4l_subdev s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; s_ctrl->sensordata->sensor_info->session_id = session_id; s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; - rc = msm_sd_register(&s_ctrl->msm_sd); - if (rc < 0) { - pr_err("failed: msm_sd_register rc %d", rc); - return rc; - } + msm_sd_register(&s_ctrl->msm_sd); msm_sensor_v4l2_subdev_fops = v4l2_subdev_fops; #ifdef CONFIG_COMPAT msm_sensor_v4l2_subdev_fops.compat_ioctl32 = @@ -152,11 +148,7 @@ static int32_t msm_sensor_driver_create_v4l_subdev s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; - rc = msm_sd_register(&s_ctrl->msm_sd); - if (rc < 0) { - pr_err("failed: msm_sd_register rc %d", rc); - return rc; - } + msm_sd_register(&s_ctrl->msm_sd); msm_cam_copy_v4l2_subdev_fops(&msm_sensor_v4l2_subdev_fops); #ifdef CONFIG_COMPAT msm_sensor_v4l2_subdev_fops.compat_ioctl32 = @@ -297,45 +289,6 @@ static int32_t msm_sensor_fill_actuator_subdevid_by_name( return rc; } -static int32_t msm_sensor_fill_laser_led_subdevid_by_name( - struct msm_sensor_ctrl_t *s_ctrl) -{ - int32_t rc = 0; - struct device_node *src_node = NULL; - uint32_t val = 0; - int32_t *laser_led_subdev_id; - struct msm_sensor_info_t *sensor_info; - struct device_node *of_node = s_ctrl->of_node; - - if (!of_node) - return -EINVAL; - - sensor_info = s_ctrl->sensordata->sensor_info; - laser_led_subdev_id = &sensor_info->subdev_id[SUB_MODULE_LASER_LED]; - /* set sudev id to -1 and try to found new id */ - *laser_led_subdev_id = -1; - - - src_node = of_parse_phandle(of_node, "qcom,laserled-src", 0); - if (!src_node) { - CDBG("%s:%d src_node NULL\n", __func__, __LINE__); - } else { - rc = of_property_read_u32(src_node, "cell-index", &val); - CDBG("%s qcom,laser led cell index %d, rc %d\n", __func__, - val, rc); - of_node_put(src_node); - src_node = NULL; - if (rc < 0) { - pr_err("%s cell index not found %d\n", - __func__, __LINE__); - return -EINVAL; - } - *laser_led_subdev_id = val; - } - - return rc; -} - static int32_t msm_sensor_fill_flash_subdevid_by_name( struct msm_sensor_ctrl_t *s_ctrl) { @@ -1020,11 +973,6 @@ CSID_TG: pr_err("%s failed %d\n", __func__, __LINE__); goto free_camera_info; } - rc = msm_sensor_fill_laser_led_subdevid_by_name(s_ctrl); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto free_camera_info; - } rc = msm_sensor_fill_ois_subdevid_by_name(s_ctrl); if (rc < 0) { @@ -1047,6 +995,12 @@ CSID_TG: pr_err("%s probe succeeded", slave_info->sensor_name); + /* + Set probe succeeded flag to 1 so that no other camera shall + * probed on this slot + */ + s_ctrl->is_probe_succeed = 1; + s_ctrl->bypass_video_node_creation = slave_info->bypass_video_node_creation; @@ -1094,11 +1048,6 @@ CSID_TG: msm_sensor_fill_sensor_info(s_ctrl, probed_info, entity_name); - /* - * Set probe succeeded flag to 1 so that no other camera shall - * probed on this slot - */ - s_ctrl->is_probe_succeed = 1; return rc; camera_power_down: diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c index 16de029071431b64a67a7a7322a56d56b4d19e94..7e3666042fde3c594774453f8b5357e5f6092607 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -77,7 +77,7 @@ static int32_t msm_sensor_driver_cmd(struct msm_sensor_init_t *s_init, cfg->entity_name); mutex_unlock(&s_init->imutex); if (rc < 0) - pr_err_ratelimited("%s failed (non-fatal) rc %d", __func__, rc); + pr_err("%s failed (non-fatal) rc %d", __func__, rc); break; case CFG_SINIT_PROBE_DONE: @@ -142,7 +142,7 @@ static long msm_sensor_init_subdev_do_ioctl( cmd = VIDIOC_MSM_SENSOR_INIT_CFG; rc = msm_sensor_init_subdev_ioctl(sd, cmd, &sensor_init_data); if (rc < 0) { - pr_err_ratelimited("%s:%d VIDIOC_MSM_SENSOR_INIT_CFG failed (non-fatal)", + pr_err("%s:%d VIDIOC_MSM_SENSOR_INIT_CFG failed (non-fatal)", __func__, __LINE__); return rc; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c index d3d48b0bbe4c4bbf4168f00590fce77d26174a10..bfb15846e73c5a677f02c420458598b1e422de0b 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c +++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c @@ -33,30 +33,6 @@ static int32_t msm_ois_power_down(struct msm_ois_ctrl_t *o_ctrl); static struct i2c_driver msm_ois_i2c_driver; -static int32_t data_type_to_num_bytes( - enum msm_camera_i2c_data_type data_type) -{ - int32_t ret_val; - - switch (data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - ret_val = 1; - break; - case MSM_CAMERA_I2C_WORD_DATA: - ret_val = 2; - break; - case MSM_CAMERA_I2C_DWORD_DATA: - ret_val = 4; - break; - default: - pr_err("unsupported data type: %d\n", - data_type); - ret_val = 1; - break; - } - return ret_val; -} - static int32_t msm_ois_download(struct msm_ois_ctrl_t *o_ctrl) { uint16_t bytes_in_tx = 0; @@ -179,9 +155,7 @@ static int32_t msm_ois_write_settings(struct msm_ois_ctrl_t *o_ctrl, uint16_t size, struct reg_settings_ois_t *settings) { int32_t rc = -EFAULT; - int32_t i = 0, num_byte_seq = 0; - uint8_t *reg_data_seq; - + int32_t i = 0; struct msm_camera_i2c_seq_reg_array *reg_setting; CDBG("Enter\n"); @@ -259,51 +233,13 @@ static int32_t msm_ois_write_settings(struct msm_ois_ctrl_t *o_ctrl, settings[i].data_type); break; } - break; } - case MSM_OIS_READ: { - switch (settings[i].data_type) { - case MSM_CAMERA_I2C_BYTE_DATA: - case MSM_CAMERA_I2C_WORD_DATA: - case MSM_CAMERA_I2C_DWORD_DATA: - - num_byte_seq = - data_type_to_num_bytes - (settings[i].data_type); - reg_data_seq = kzalloc(sizeof(uint32_t), - GFP_KERNEL); - if (!reg_data_seq) - return -ENOMEM; - - rc = msm_camera_cci_i2c_read_seq - (&o_ctrl->i2c_client, - settings[i].reg_addr, - reg_data_seq, - num_byte_seq); - - memcpy(&settings[i].reg_data, - reg_data_seq, sizeof(uint32_t)); - - CDBG("ois data read 0x%x from address 0x%x", - settings[i].reg_addr, - settings[i].reg_data); - - kfree(reg_data_seq); - reg_data_seq = NULL; - - break; - default: - pr_err("Unsupport data type for MSM_OIS_READ: %d\n", - settings[i].data_type); - break; - } - break; } if (rc < 0) break; - } } + CDBG("Exit\n"); return rc; } @@ -412,7 +348,7 @@ static int32_t msm_ois_control(struct msm_ois_ctrl_t *o_ctrl, struct msm_ois_set_info_t *set_info) { struct reg_settings_ois_t *settings = NULL; - int32_t rc = 0, i = 0; + int32_t rc = 0; struct msm_camera_cci_client *cci_client = NULL; CDBG("Enter\n"); @@ -454,18 +390,6 @@ static int32_t msm_ois_control(struct msm_ois_ctrl_t *o_ctrl, rc = msm_ois_write_settings(o_ctrl, set_info->ois_params.setting_size, settings); - - for (i = 0; i < set_info->ois_params.setting_size; i++) { - if (set_info->ois_params.settings[i].i2c_operation - == MSM_OIS_READ) { - set_info->ois_params.settings[i].reg_data = - settings[i].reg_data; - CDBG("ois_data at addr 0x%x is 0x%x", - set_info->ois_params.settings[i].reg_addr, - set_info->ois_params.settings[i].reg_data); - } - } - kfree(settings); if (rc < 0) { pr_err("Error\n"); @@ -478,6 +402,7 @@ static int32_t msm_ois_control(struct msm_ois_ctrl_t *o_ctrl, return rc; } + static int32_t msm_ois_config(struct msm_ois_ctrl_t *o_ctrl, void __user *argp) { @@ -690,13 +615,11 @@ static long msm_ois_subdev_ioctl(struct v4l2_subdev *sd, pr_err("o_ctrl->i2c_client.i2c_func_tbl NULL\n"); return -EINVAL; } - mutex_lock(o_ctrl->ois_mutex); rc = msm_ois_power_down(o_ctrl); if (rc < 0) { pr_err("%s:%d OIS Power down failed\n", __func__, __LINE__); } - mutex_unlock(o_ctrl->ois_mutex); return msm_ois_close(sd, NULL); default: return -ENOIOCTLCMD; @@ -895,10 +818,6 @@ static long msm_ois_subdev_do_ioctl( parg = &ois_data; break; } - break; - case VIDIOC_MSM_OIS_CFG: - pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd); - return -EINVAL; } rc = msm_ois_subdev_ioctl(sd, cmd, parg); diff --git a/drivers/media/platform/msm/camera_v2/sensor/sony_camera_v4l2.c b/drivers/media/platform/msm/camera_v2/sensor/sony_camera_v4l2.c new file mode 100644 index 0000000000000000000000000000000000000000..1560851fa270905973773df81d9be9bd3b757753 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/sony_camera_v4l2.c @@ -0,0 +1,2439 @@ +/* drivers/media/platform/msm/camera_v2/sensor/sony_camera_v4l2.c + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef DEBUG +#define DEBUG +#endif + +#define ENABLE_LOGE +#define ENABLE_LOGI +/*#define ENABLE_LOGD*/ + +#include +#include +#include +#include +#include "camera.h" +#include "msm_sensor.h" +#include "msm_camera_i2c.h" +#include "msm_cci.h" +#include "msm_camera_i2c_mux.h" +#include "msm_camera_io_util.h" +#include "sony_camera_v4l2.h" +#include + +#ifdef ENABLE_LOGE +#define LOGE(f, a...) dev_err(camera_device, "%s: " f, __func__, ##a) +#else +#define LOGE(f, a...) +#endif + +#ifdef ENABLE_LOGD +#define LOGD(f, a...) dev_dbg(camera_device, "%s: " f, __func__, ##a) +#else +#define LOGD(f, a...) +#endif + +#ifdef ENABLE_LOGI +#define LOGI(f, a...) dev_info(camera_device, "%s: " f, __func__, ##a) +#else +#define LOGI(f, a...) +#endif + +#define I2C_MAX_DATA_LEN 256 +#define SENSOR_NAME_LEN 8 +#define EEPROM_MAX_DATA_LEN 2048 +#define EEPROM_READ_FREQ_MODE 1 +#define SENSOR_MCLK_DEFAULT 8000000 + +#define SENSOR_ID_MT9M114 0x2481 +#define SENSOR_ID_MT9V115 0x2284 +#define MODULE_STW01BM0 "STW01BM0" +#define MODULE_APT01BM0 "APT01BM0" +#define MODULE_APT00YP1 "APT00YP1" +#define MODULE_STW00YP1 "STW00YP1" +#define CAMERA_DEV_NAME "sony_camera_%d" +#define CAMERA_THERMAL_NAME_0 "sony_camera_0" +#define CAMERA_THERMAL_NAME_1 "sony_camera_1" +#define CAPS_MAX_STR_LEN 32 + +#define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend" +#define CAM_SENSOR_PINCTRL_STATE_DEFAULT "cam_default" + +struct sony_camera_data { + bool probe_done; + bool gpio_requested; + struct device *d; + struct msm_sensor_ctrl_t s_ctrl; + uint8_t buf[I2C_MAX_DATA_LEN]; + uint8_t eeprom[EEPROM_MAX_DATA_LEN]; + uint16_t eeprom_len; + const struct sony_camera_module *module; + struct regulator *cam_vio; + struct regulator *cam_vana; + struct regulator *cam_vdig; + struct regulator *cam_vaf; + struct regulator *cam_vio_gpio; + struct regulator *cam_vana_gpio; + struct regulator *cam_vdig_gpio; + struct regulator *cam_vaf_gpio; + struct clk *clk_handle[2]; + struct device info_dev; + bool power_up_done; + struct thermal_zone_device *thermal_zone_dev; + int32_t thermal_sensor_temp; + int thermal_ret_val; + uint32_t sof_irq; + int sof_gpio; +}; + +struct camera_read_info { + uint32_t mount_angle; + uint32_t sensor_rotation; + uint32_t sensor_facing; + uint32_t sensor_config_delay_num; + uint32_t sensor_config_delay[MAX_CONFIG_DELAY_NUM]; + uint32_t temperature_check_skip_num; + uint32_t total_pixel_number_w; + uint32_t total_pixel_number_h; + uint32_t active_pixel_number_x; + uint32_t active_pixel_number_y; + uint32_t active_pixel_number_w; + uint32_t active_pixel_number_h; + uint32_t min_focus_distance; + uint32_t hyper_focal_distance; + char diagonal_len[CAPS_MAX_STR_LEN]; + char unit_cell_size_w[CAPS_MAX_STR_LEN]; + char unit_cell_size_h[CAPS_MAX_STR_LEN]; + char min_f_number[CAPS_MAX_STR_LEN]; + char max_f_number[CAPS_MAX_STR_LEN]; + uint32_t min_focus_pos; + uint32_t max_focus_pos; + uint32_t min_focus_dac; + uint32_t max_focus_dac; + uint32_t focus_inf_range_offset; + uint32_t focus_macro_range_offset; + uint32_t focus_lens_stroke_inf_to_1m; + uint32_t focus_lens_stroke_1m_to_macro; + uint32_t focus_lens_stroke_inf_to_macro; + uint32_t focus_calc_type; + uint32_t focus_wob_time; + uint32_t has_3a; + uint32_t has_focus_actuator; + uint32_t has_pdaf; + uint32_t has_rs; + uint32_t has_multi_output; + uint32_t has_super_slow; + uint32_t has_sub_sensor; + uint32_t has_aube; + uint32_t has_flicker_detector; + uint32_t has_hw_sof; + uint32_t has_hdr; + uint32_t has_seamless_mode_change; + uint32_t has_gph; + uint32_t pdaf_free_area_num; + uint32_t pdaf_fixed_area_size_w; + uint32_t pdaf_fixed_area_size_h; + uint32_t eeprom_size; + uint8_t eeprom[EEPROM_MAX_DATA_LEN]; + uint32_t pll_num; + uint32_t pll[MAX_PLL_NUM]; +}; + +struct camera_write_info { + int32_t sensor_temp; +}; + +static struct sony_camera_info *camera_info; +static struct sony_camera_data camera_data[]; +static struct device *camera_device; +static DEFINE_MUTEX(sensor_mutex); +static DEFINE_MUTEX(af_standby_mutex); +static struct task_struct *af_task; +static uint16_t sensor_num; +static struct msm_cam_clk_info cam_clk_info[] = { + {"cam_src_clk", 0}, + {"cam_clk", -1}, +}; + +static struct msm_sensor_power_setting sony_power_setting[] = { + { + .seq_type = 0, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +#if defined(CONFIG_LEDS_QPNP_RGB_SCALE) && (CONFIG_FRONT_CAMERA_LED_SCALE > 0) +extern int qpnp_led_set_rgb_scale(int scale); +#endif + +static int32_t sony_util_get_context(struct msm_sensor_ctrl_t *s_ctrl) +{ + uint16_t i; + char sensor_name[CAPS_MAX_STR_LEN]; + + memset(sensor_name, 0, sizeof(sensor_name)); + for (i = 0; i < sensor_num; i++) { + snprintf(sensor_name, sizeof(sensor_name), CAMERA_DEV_NAME, i); + if (!strncmp(s_ctrl->sensordata->sensor_name, + sensor_name, sizeof(sensor_name))) + break; + } + + if (camera_data[i].d) + camera_device = camera_data[i].d; + + return i; +} + +static int sony_util_camera_info_init(struct platform_device *pdev, uint16_t id) +{ + int rc = 0; + int count = 0; + uint16_t i = 0; + uint16_t j = 0; + uint32_t val_u32[4] = {0}; + struct device_node *of_node = pdev->dev.of_node; + struct device_node *of_node_power_sequence = NULL; + struct device_node *of_node_modules = NULL; + struct device_node *of_node_modules_power_off = NULL; + struct device_node *of_node_modules_power_on = NULL; + const int8_t *power_order_name = NULL; + + rc = of_property_read_u32(of_node, "sony,i2c_addr", &val_u32[0]); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + camera_info[id].i2c_addr = val_u32[0]; + + rc = of_property_read_u32(of_node, "sony,eeprom_addr", &val_u32[0]); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + camera_info[id].eeprom_addr = val_u32[0]; + + rc = of_property_read_u32(of_node, "sony,eeprom_type", &val_u32[0]); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + camera_info[id].eeprom_type = val_u32[0]; + + rc = of_property_read_u32(of_node, "sony,eeprom_max_len", &val_u32[0]); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + camera_info[id].eeprom_max_len = val_u32[0]; + + rc = of_property_read_u32(of_node, "sony,gpio_af", &val_u32[0]); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + camera_info[id].gpio_af = val_u32[0]; + + rc = of_property_read_u32(of_node, "sony,subdev_code", &val_u32[0]); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + camera_info[id].subdev_code = val_u32[0]; + + rc = of_property_read_u32_array(of_node, "interrupts", &val_u32[0], 2); + if (rc < 0) { + camera_data[id].sof_gpio = -1; + } else { + camera_data[id].sof_gpio = val_u32[0]; + } + + of_node_power_sequence = of_find_node_by_name(of_node, + "sony,camera_modules"); + if (!of_node_power_sequence) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -EFAULT; + goto fail; + } + + count = of_property_count_strings(of_node_power_sequence, + "module_names"); + if (count < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -EFAULT; + goto fail; + } + camera_info[id].modules_num = count; + + camera_info[id].modules = kzalloc( + sizeof(struct sony_camera_module) * count, GFP_KERNEL); + if (!camera_info[id].modules) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto fail; + } + + for (i = 0; i < camera_info[id].modules_num; i++) { + rc = of_property_read_string_index(of_node_power_sequence, + "module_names", i, + (const char **)(&camera_info[id].modules[i].name)); + LOGD("%s name[%d] = %s\n", __func__, i, + camera_info[id].modules[i].name); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + } + + for (i = 0; i < camera_info[id].modules_num; i++) { + of_node_modules = of_find_node_by_name(of_node_power_sequence, + camera_info[id].modules[i].name); + if (!of_node_modules) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -EFAULT; + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "mount_angle", + &camera_info[id].modules[i].mount_angle); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "sensor_rotation", + &camera_info[id].modules[i].sensor_rotation); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "sensor_facing", + &camera_info[id].modules[i].sensor_facing); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "sensor_config_delay_num", + &camera_info[id].modules[i].sensor_config_delay_num); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + if (camera_info[id].modules[i].sensor_config_delay_num > MAX_CONFIG_DELAY_NUM) { + LOGE("%s failed %d sensor_config_delay_num %d\n", + __func__, __LINE__, + camera_info[id].modules[i].sensor_config_delay_num); + camera_info[id].modules[i].sensor_config_delay_num = MAX_CONFIG_DELAY_NUM; + } + + rc = of_property_read_u32_array(of_node_modules, + "sensor_config_delay", + camera_info[id].modules[i].sensor_config_delay, + camera_info[id].modules[i].sensor_config_delay_num); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "temperature_check_skip_num", + &camera_info[id].modules[i].temperature_check_skip_num); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "total_pixel_number_w", + &camera_info[id].modules[i].total_pixel_number_w); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "total_pixel_number_h", + &camera_info[id].modules[i].total_pixel_number_h); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "active_pixel_number_x", + &camera_info[id].modules[i].active_pixel_number_x); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "active_pixel_number_y", + &camera_info[id].modules[i].active_pixel_number_y); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + rc = of_property_read_u32(of_node_modules, + "active_pixel_number_w", + &camera_info[id].modules[i].active_pixel_number_w); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "active_pixel_number_h", + &camera_info[id].modules[i].active_pixel_number_h); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "min_focus_distance", + &camera_info[id].modules[i].min_focus_distance); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "hyper_focal_distance", + &camera_info[id].modules[i].hyper_focal_distance); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_string(of_node_modules, + "diagonal_len", + (const char **)( + &camera_info[id].modules[i].diagonal_len)); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_string(of_node_modules, + "unit_cell_size_w", + (const char **)( + &camera_info[id].modules[i].unit_cell_size_w)); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_string(of_node_modules, + "unit_cell_size_h", + (const char **)( + &camera_info[id].modules[i].unit_cell_size_h)); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_string(of_node_modules, + "min_f_number", + (const char **)( + &camera_info[id].modules[i].min_f_number)); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_string(of_node_modules, + "max_f_number", + (const char **)( + &camera_info[id].modules[i].max_f_number)); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "min_focus_pos", + &camera_info[id].modules[i].min_focus_pos); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "max_focus_pos", + &camera_info[id].modules[i].max_focus_pos); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "min_focus_dac", + &camera_info[id].modules[i].min_focus_dac); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "max_focus_dac", + &camera_info[id].modules[i].max_focus_dac); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "focus_inf_range_offset", + &camera_info[id].modules[i].focus_inf_range_offset); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "focus_macro_range_offset", + &camera_info[id].modules[i].focus_macro_range_offset); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "focus_lens_stroke_inf_to_1m", + &camera_info[id].modules[i].focus_lens_stroke_inf_to_1m); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "focus_lens_stroke_1m_to_macro", + &camera_info[id].modules[i].focus_lens_stroke_1m_to_macro); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "focus_lens_stroke_inf_to_macro", + &camera_info[id].modules[i].focus_lens_stroke_inf_to_macro); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "focus_calc_type", + &camera_info[id].modules[i].focus_calc_type); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "focus_wob_time", + &camera_info[id].modules[i].focus_wob_time); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_3a", + &camera_info[id].modules[i].has_3a); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_focus_actuator", + &camera_info[id].modules[i].has_focus_actuator); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "need_standby_af", + &camera_info[id].modules[i].need_standby_af); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "i2c_freq_mode", + &camera_info[id].modules[i].i2c_freq_mode); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_pdaf", + &camera_info[id].modules[i].has_pdaf); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_rs", + &camera_info[id].modules[i].has_rs); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_multi_output", + &camera_info[id].modules[i].has_multi_output); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_super_slow", + &camera_info[id].modules[i].has_super_slow); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_sub_sensor", + &camera_info[id].modules[i].has_sub_sensor); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_aube", + &camera_info[id].modules[i].has_aube); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_flicker_detector", + &camera_info[id].modules[i].has_flicker_detector); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_hdr", + &camera_info[id].modules[i].has_hdr); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_seamless_mode_change", + &camera_info[id].modules[i].has_seamless_mode_change); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "has_gph", + &camera_info[id].modules[i].has_gph); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "pdaf_free_area_num", + &camera_info[id].modules[i].pdaf_free_area_num); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "pdaf_fixed_area_size_w", + &camera_info[id].modules[i].pdaf_fixed_area_size_w); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "pdaf_fixed_area_size_h", + &camera_info[id].modules[i].pdaf_fixed_area_size_h); + + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32(of_node_modules, + "pll_num", + &camera_info[id].modules[i].pll_num); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32_array(of_node_modules, + "pll", + camera_info[id].modules[i].pll, + camera_info[id].modules[i].pll_num); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + of_node_modules_power_off = of_find_node_by_name( + of_node_modules, + "power_off"); + if (!of_node_modules_power_off) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -EFAULT; + goto fail; + } + + count = of_property_count_strings(of_node_modules_power_off, + "commands"); + if (count < 0) { + LOGE("%s failed power off commands 0\n", __func__); + rc = -EFAULT; + goto fail; + } + camera_info[id].modules[i].seq_off = kzalloc( + sizeof(struct sony_camera_seq) * count, GFP_KERNEL); + if (!camera_info[id].modules[i].seq_off) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto fail; + } + + for (j = 0; j < count; j++) { + rc = of_property_read_string_index( + of_node_modules_power_off, + "commands", j, + (const char **)(&power_order_name)); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + rc = of_property_read_u32_array( + of_node_modules_power_off, power_order_name, + &val_u32[0], 4); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + camera_info[id].modules[i].seq_off[j].cmd = + val_u32[0]; + camera_info[id].modules[i].seq_off[j].val1 = + val_u32[1]; + camera_info[id].modules[i].seq_off[j].val2 = + val_u32[2]; + camera_info[id].modules[i].seq_off[j].wait = + val_u32[3]; + } + + of_node_modules_power_on = of_find_node_by_name(of_node_modules, + "power_on"); + if (!of_node_modules_power_on) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -EFAULT; + goto fail; + } + + count = of_property_count_strings(of_node_modules_power_on, + "commands"); + if (count < 0) { + LOGE("%s failed power on commands 0\n", __func__); + rc = -EFAULT; + goto fail; + } + + camera_info[id].modules[i].seq_on = kzalloc( + sizeof(struct sony_camera_seq) * count, GFP_KERNEL); + if (!camera_info[id].modules[i].seq_on) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto fail; + } + + for (j = 0; j < count; j++) { + rc = of_property_read_string_index( + of_node_modules_power_on, + "commands", j, + (const char **)(&power_order_name)); + if (rc < 0) { + LOGE("%s failed %d j=%d count=%d\n", __func__, __LINE__, j, count); + goto fail; + } + + rc = of_property_read_u32_array( + of_node_modules_power_on, power_order_name, + &val_u32[0], 4); + if (rc < 0) { + LOGE("%s failed %d j=%d count=%d\n", __func__, __LINE__, j, count); + goto fail; + } + camera_info[id].modules[i].seq_on[j].cmd = + val_u32[0]; + camera_info[id].modules[i].seq_on[j].val1 = + val_u32[1]; + camera_info[id].modules[i].seq_on[j].val2 = + val_u32[2]; + camera_info[id].modules[i].seq_on[j].wait = + val_u32[3]; + } + } + + rc = of_property_read_string(of_node_power_sequence, + "default_module_name", + &camera_info[id].default_module_name); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto fail; + } + + return 0; +fail: + if (camera_info[id].modules) { + for (i = 0; i < camera_info[id].modules_num; i++) { + kfree(camera_info[id].modules[i].seq_on); + kfree(camera_info[id].modules[i].seq_off); + } + kfree(camera_info[id].modules); + } + memset(&(camera_info[id]), 0, sizeof(struct sony_camera_info)); + + return rc; +} + +static int sony_util_camera_info_deinit(uint16_t id) +{ + uint16_t i = 0; + + if (camera_info[id].modules) { + for (i = 0; i < camera_info[id].modules_num; i++) { + kfree(camera_info[id].modules[i].seq_on); + kfree(camera_info[id].modules[i].seq_off); + } + kfree(camera_info[id].modules); + } + memset(&(camera_info[id]), 0, sizeof(struct sony_camera_info)); + + return 0; +} + +static int sony_util_gpio_init(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint16_t id = sony_util_get_context(s_ctrl); + + if (!camera_data[id].gpio_requested) { + rc = msm_camera_request_gpio_table( + s_ctrl->sensordata->power_info + .gpio_conf->cam_gpio_req_tbl, + s_ctrl->sensordata->power_info + .gpio_conf->cam_gpio_req_tbl_size, + 1); + if (rc == 0) + camera_data[id].gpio_requested = true; + } + + return rc; +} + +static int sony_util_gpio_deinit(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint16_t id = sony_util_get_context(s_ctrl); + + if (camera_data[id].gpio_requested) { + rc = msm_camera_request_gpio_table( + s_ctrl->sensordata->power_info + .gpio_conf->cam_gpio_req_tbl, + s_ctrl->sensordata->power_info + .gpio_conf->cam_gpio_req_tbl_size, + 0); + camera_data[id].gpio_requested = false; + } + + return rc; +} + +static int sony_util_gpio_set(struct msm_sensor_ctrl_t *s_ctrl, + int gpio_pin, int value) +{ + int rc = 0; + uint16_t id = sony_util_get_context(s_ctrl); + + if (camera_data[id].gpio_requested) + gpio_set_value_cansleep(gpio_pin, value); + else + rc = -EPERM; + + return rc; +} + +static int sony_util_vreg_set(struct msm_sensor_ctrl_t *s_ctrl, + struct sony_camera_data *data, enum sony_camera_cmd cmd, int level, + int op_mode) +{ + int rc = 0; + struct regulator *vreg; + struct device *dev = &s_ctrl->pdev->dev; + + if (cmd == SONY_CAM_VDIG) { + if (data->cam_vdig) { + vreg = data->cam_vdig; + } else { + vreg = regulator_get(dev, "cam_vdig"); + if (IS_ERR(vreg)) { + LOGE("could not get cam_vdig, vreg = %ld\n", + PTR_ERR(vreg)); + rc = -ENODEV; + goto exit; + } + data->cam_vdig = vreg; + } + } else if (cmd == SONY_CAM_VIO) { + if (data->cam_vio) { + vreg = data->cam_vio; + } else { + vreg = regulator_get(dev, "cam_vio"); + if (IS_ERR(vreg)) { + LOGE("could not get cam_vio, vreg = %ld\n", + PTR_ERR(vreg)); + rc = -ENODEV; + goto exit; + } + data->cam_vio = vreg; + } + } else if (cmd == SONY_CAM_VANA) { + if (data->cam_vana) { + vreg = data->cam_vana; + } else { + vreg = regulator_get(dev, "cam_vana"); + if (IS_ERR(vreg)) { + LOGE("could not get cam_vana, vreg = %ld\n", + PTR_ERR(vreg)); + rc = -ENODEV; + goto exit; + } + data->cam_vana = vreg; + } + } else if (cmd == SONY_CAM_VAF) { + if (data->cam_vaf) { + vreg = data->cam_vaf; + } else { + vreg = regulator_get(dev, "cam_vaf"); + if (IS_ERR(vreg)) { + LOGE("could not get cam_vaf, vreg = %ld\n", + PTR_ERR(vreg)); + rc = -ENODEV; + goto exit; + } + data->cam_vaf = vreg; + } + } else if (cmd == SONY_CAM_VDIG_GPIO) { + if (data->cam_vdig_gpio) { + vreg = data->cam_vdig_gpio; + } else { + vreg = regulator_get(dev, "cam_vdig_gpio"); + if (IS_ERR(vreg)) { + LOGE("could not get cam_vdig_gpio, vreg = %ld\n", + PTR_ERR(vreg)); + rc = -ENODEV; + goto exit; + } + data->cam_vdig_gpio = vreg; + } + } else if (cmd == SONY_CAM_VIO_GPIO) { + if (data->cam_vio_gpio) { + vreg = data->cam_vio_gpio; + } else { + vreg = regulator_get(dev, "cam_vio_gpio"); + if (IS_ERR(vreg)) { + LOGE("could not get cam_vio_gpio, vreg = %ld\n", + PTR_ERR(vreg)); + rc = -ENODEV; + goto exit; + } + data->cam_vio_gpio = vreg; + } + } else if (cmd == SONY_CAM_VANA_GPIO) { + if (data->cam_vana_gpio) { + vreg = data->cam_vana_gpio; + } else { + vreg = regulator_get(dev, "cam_vana_gpio"); + if (IS_ERR(vreg)) { + LOGE("could not get cam_vana_gpio, vreg = %ld\n", + PTR_ERR(vreg)); + rc = -ENODEV; + goto exit; + } + data->cam_vana_gpio = vreg; + } + } else if (cmd == SONY_CAM_VAF_GPIO) { + if (data->cam_vaf_gpio) { + vreg = data->cam_vaf_gpio; + } else { + vreg = regulator_get(dev, "cam_vaf_gpio"); + if (IS_ERR(vreg)) { + LOGE("could not get cam_vaf_gpio, vreg = %ld\n", + PTR_ERR(vreg)); + rc = -ENODEV; + goto exit; + } + data->cam_vaf_gpio = vreg; + } + } else { + rc = -EINVAL; + LOGE("invalid resource\n"); + goto exit; + } + + level *= 1000; + if (level >= 0) { + if (level > 0) { + rc = regulator_set_voltage(vreg, level, level); + if (rc < 0) + goto set_voltage_fail; + } + if (op_mode > 0) { + rc = regulator_set_load(vreg, op_mode); + if (rc < 0) + goto set_voltage_fail; + } + rc = regulator_enable(vreg); + if (rc < 0) + goto enable_fail; + } else { + if (op_mode == 0) + (void)regulator_set_load(vreg, 0); + (void)regulator_disable(vreg); + regulator_put(vreg); + } + goto exit; + +enable_fail: + (void)regulator_set_load(vreg, 0); + +set_voltage_fail: + regulator_put(vreg); + +exit: + if (rc < 0 || level < 0) { + if (vreg == data->cam_vdig) + data->cam_vdig = NULL; + else if (vreg == data->cam_vio) + data->cam_vio = NULL; + else if (vreg == data->cam_vana) + data->cam_vana = NULL; + else if (vreg == data->cam_vaf) + data->cam_vaf = NULL; + else if (vreg == data->cam_vdig_gpio) + data->cam_vdig_gpio = NULL; + else if (vreg == data->cam_vio_gpio) + data->cam_vio_gpio = NULL; + else if (vreg == data->cam_vana_gpio) + data->cam_vana_gpio = NULL; + else if (vreg == data->cam_vaf_gpio) + data->cam_vaf_gpio = NULL; + } + + if (rc < 0) + LOGE("error happened (%d)\n", rc); + return rc; +} + +static int sony_util_mclk_set(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + int rc; + struct device *dev = &s_ctrl->pdev->dev; + uint16_t id = sony_util_get_context(s_ctrl); + + if (value >= 0) { + if (value == 0) + cam_clk_info[0].clk_rate = SENSOR_MCLK_DEFAULT; + else + cam_clk_info[0].clk_rate = (long)value; + + rc = msm_cam_clk_enable( + dev, + (struct msm_cam_clk_info *)cam_clk_info, + (struct clk **)&camera_data[id].clk_handle[0], + ARRAY_SIZE(cam_clk_info), 1); + } else { + rc = msm_cam_clk_enable( + dev, + (struct msm_cam_clk_info *)cam_clk_info, + (struct clk **)&camera_data[id].clk_handle[0], + ARRAY_SIZE(cam_clk_info), 0); + } + + if (rc < 0) + LOGE("error happened (%d)\n", rc); + + return rc; +} + +static int sony_util_i2c_mux_enable(struct msm_camera_i2c_conf *i2c_conf) +{ + struct v4l2_subdev *i2c_mux_sd = + dev_get_drvdata(&i2c_conf->mux_dev->dev); + + v4l2_subdev_call(i2c_mux_sd, core, ioctl, + VIDIOC_MSM_I2C_MUX_INIT, NULL); + v4l2_subdev_call(i2c_mux_sd, core, ioctl, + VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode); + return 0; +} + +static int sony_util_i2c_mux_disable(struct msm_camera_i2c_conf *i2c_conf) +{ + struct v4l2_subdev *i2c_mux_sd = + dev_get_drvdata(&i2c_conf->mux_dev->dev); + + v4l2_subdev_call(i2c_mux_sd, core, ioctl, + VIDIOC_MSM_I2C_MUX_RELEASE, NULL); + return 0; +} + +static int sony_util_cci_init(struct msm_camera_i2c_client *client) +{ + return msm_sensor_cci_i2c_util(client, MSM_CCI_INIT); +} + +static int sony_util_cci_deinit(struct msm_camera_i2c_client *client) +{ + return msm_sensor_cci_i2c_util(client, MSM_CCI_RELEASE); +} + +static int sony_util_cam_i2c_read(struct msm_sensor_ctrl_t *s_ctrl, + uint8_t slave_addr, uint32_t addr, + uint8_t type, uint16_t len, uint8_t *data) +{ + int rc = 0; + uint16_t i = 0; + uint16_t read_addr = 0x00; + uint16_t read_data = 0x00; + uint16_t orig_sid; + uint16_t orig_addr_type; + + orig_sid = s_ctrl->sensor_i2c_client->cci_client->sid; + orig_addr_type = s_ctrl->sensor_i2c_client->addr_type; + + s_ctrl->sensor_i2c_client->addr_type = type; + s_ctrl->sensor_i2c_client->cci_client->sid = slave_addr >> 1; + + for (i = 0; i < len; i++) { + read_addr = addr + i; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + read_addr, + &read_data, + MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + LOGE("slave0x%04x,addr0x%04x,type0x%02x,len0x%02x\n", + slave_addr, addr, type, len); + LOGE("i2c read failed(%d)\n", rc); + rc = -EIO; + goto exit; + } + data[i] = (uint8_t)(read_data & 0xFF); + } + +exit: + s_ctrl->sensor_i2c_client->cci_client->sid = orig_sid; + s_ctrl->sensor_i2c_client->addr_type = orig_addr_type; + + return rc; +} + +static int sony_util_cam_i2c_write(struct msm_sensor_ctrl_t *s_ctrl, + uint8_t slave_addr, uint32_t addr, uint8_t type, + uint16_t len, uint8_t *data) +{ + int rc = 0; + uint16_t i = 0; + uint16_t write_addr = 0x00; + uint16_t write_data = 0x00; + uint16_t orig_sid; + uint16_t orig_addr_type; + + orig_sid = s_ctrl->sensor_i2c_client->cci_client->sid; + orig_addr_type = s_ctrl->sensor_i2c_client->addr_type; + + s_ctrl->sensor_i2c_client->addr_type = type; + s_ctrl->sensor_i2c_client->cci_client->sid = slave_addr >> 1; + + for (i = 0; i < len; i++) { + write_data = data[i]; + write_addr = addr + i; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, + write_addr, + write_data, + MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + LOGE("slave0x%04x,addr0x%04x,type0x%02x,len0x%02x,data", + slave_addr, addr, type, len); + for (i = 0; i < len; i++) + LOGE("0x%02x ", *(data + i)); + LOGE("i2c write failed(%d)\n", rc); + rc = -EIO; + goto exit; + } + } + +exit: + s_ctrl->sensor_i2c_client->cci_client->sid = orig_sid; + s_ctrl->sensor_i2c_client->addr_type = orig_addr_type; + + return rc; +} + +static int sony_util_power_ctrl(struct msm_sensor_ctrl_t *s_ctrl, + struct sony_camera_data *data, bool on) +{ + int rc = 0; + uint16_t id = sony_util_get_context(s_ctrl); + const struct sony_camera_module *mod = data->probe_done ? + data->module : camera_info[id].modules; + const struct sony_camera_seq *seq = on ? mod->seq_on : mod->seq_off; + + while (seq->cmd != EXIT) { + uint8_t iodt = 0x00; + switch (seq->cmd) { + case SONY_GPIO_RESET: + rc = sony_util_gpio_set(s_ctrl, + s_ctrl->sensordata + ->power_info.gpio_conf + ->cam_gpio_req_tbl[1].gpio, + seq->val1); + break; + case SONY_GPIO_AF: + if (camera_info[id].gpio_af <= 0) { + rc = -EPERM; + break; + } + + rc = sony_util_gpio_set(s_ctrl, + camera_info[id].gpio_af, seq->val1); + break; + case SONY_CAM_VDIG: + case SONY_CAM_VIO: + case SONY_CAM_VANA: + case SONY_CAM_VAF: + case SONY_CAM_VIO_GPIO: + case SONY_CAM_VANA_GPIO: + case SONY_CAM_VDIG_GPIO: + case SONY_CAM_VAF_GPIO: + rc = sony_util_vreg_set(s_ctrl, + data, seq->cmd, seq->val1, seq->val2); + break; + case SONY_CAM_CLK: + rc = sony_util_mclk_set(s_ctrl, seq->val1); + break; + case SONY_I2C_WRITE: + rc = sony_util_cam_i2c_write(s_ctrl, + camera_info[id].i2c_addr, + seq->val1, + MSM_CAMERA_I2C_WORD_ADDR, + 1, + &iodt); + break; + default: + goto exit; + } + mdelay(seq->wait); + if (rc < 0 && on) + goto exit; + seq++; + } +exit: + return rc; +} + +static int sony_util_sub_camera_af_standby_task(void *sdata) +{ + int rc = 0; + struct msm_sensor_ctrl_t *s_ctrl = (struct msm_sensor_ctrl_t *)sdata; + struct sony_camera_data *main_data = &camera_data[0]; + struct sony_camera_data *sub_data = &camera_data[1]; + struct msm_camera_sensor_board_info *sub_sensordata = + sub_data->s_ctrl.sensordata; + uint16_t id = sony_util_get_context(s_ctrl); + uint8_t data[2]; + + mutex_lock(&af_standby_mutex); + if (id == 0 && + main_data->probe_done == true && + sub_data->probe_done == true && + sub_data->module->need_standby_af && + !sub_data->power_up_done) { + int r = 0; + uint32_t i = 0; + + rc = sony_util_cci_init(sub_data->s_ctrl.sensor_i2c_client); + if (rc < 0) { + LOGE("sub camera cci_init failed\n"); + goto exit; + } + if (sub_sensordata->power_info.i2c_conf && + sub_sensordata->power_info.i2c_conf->use_i2c_mux) + sony_util_i2c_mux_enable( + sub_sensordata->power_info.i2c_conf); + for (i = 0; i < 1000; i++) { + r = sony_util_cam_i2c_read(&sub_data->s_ctrl, + 0x72 << 1, 0xB3, MSM_CAMERA_I2C_BYTE_ADDR, + 1, data); + if (r < 0) { + LOGE("sub camera af read failed\n"); + goto sub_exit; + } else if (!data[0]) { + LOGD("wake up flag = 0x%0x\n", data[0]); + break; + } + } + if (i >= 1000) { + LOGE("sub camera af wake up check failed. i:%d\n", i); + goto sub_exit; + } + data[0] = 0x02; + r = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0xF3, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + if (r < 0) + goto sub_exit; + data[0] = 0x20; + r = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0xF2, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + if (r < 0) + goto sub_exit; + data[0] = 0x02; + r = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0xA1, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + if (r < 0) + goto sub_exit; + data[0] = 0xC0; + r = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0x98, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + if (r < 0) + goto sub_exit; + data[0] = 0x28; + r = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0x96, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + if (r < 0) + goto sub_exit; + data[0] = 0x80; + r = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0xF6, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + LOGD("%s sub camera standby down\n", __func__); +sub_exit: + if (sub_sensordata->power_info.i2c_conf && + sub_sensordata->power_info.i2c_conf->use_i2c_mux) + sony_util_i2c_mux_disable( + sub_sensordata->power_info.i2c_conf); + rc = sony_util_cci_deinit(sub_data->s_ctrl.sensor_i2c_client); + if (rc < 0) + LOGE("sub camera cci_deinit failed\n"); + if (r < 0) + rc = -EINVAL; + } else if (id == 1 && + main_data->probe_done == true && + sub_data->probe_done == true && + sub_data->module->need_standby_af && + main_data->power_up_done) { + data[0] = 0x00; + rc = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0xF6, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + if (rc < 0) + goto exit; + data[0] = 0x20; + rc = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0x96, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + if (rc < 0) + goto exit; + data[0] = 0x00; + rc = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0x98, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + if (rc < 0) + goto exit; + data[0] = 0x01; + rc = sony_util_cam_i2c_write(&sub_data->s_ctrl, + 0x72 << 1, 0xE0, MSM_CAMERA_I2C_BYTE_ADDR, 1, data); + LOGD("%s sub camera resume down\n", __func__); + } +exit: + af_task = NULL; + mutex_unlock(&af_standby_mutex); + return rc; +} + +static int sony_camera_thermal_get_temp(struct thermal_zone_device *thermal, + int *temp) +{ + int rc = 0; + int id = 0; + + if (!temp) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -EPERM; + goto error; + } + + if (!strncmp(thermal->type, CAMERA_THERMAL_NAME_0, + sizeof(CAMERA_THERMAL_NAME_0))) { + id = 0; + } else if (!strncmp(thermal->type, CAMERA_THERMAL_NAME_1, + sizeof(CAMERA_THERMAL_NAME_1))) { + id = 1; + } else { + rc = -EPERM; + goto error; + } + + if (camera_data[id].thermal_ret_val < 0) + rc = camera_data[id].thermal_ret_val; + else + *temp = (int)camera_data[id].thermal_sensor_temp; + LOGD("%s %d, id = %d rc = %d *temp = %d\n", + __func__, __LINE__, id, rc, *temp); + +error: + return rc; +} + +static struct thermal_zone_device_ops sony_camera_thermal_ops = { + .get_temp = sony_camera_thermal_get_temp, +}; + +static ssize_t sony_camera_info_read(struct device *ldev, + struct device_attribute *attr, char *buf) +{ + char sensor_name[CAPS_MAX_STR_LEN]; + int id = 0; + uint16_t info_len = 0; + struct camera_read_info *info = (struct camera_read_info *)buf; + + memset(sensor_name, 0, sizeof(sensor_name)); + for (id = 0; id < sensor_num; id++) { + snprintf(sensor_name, sizeof(sensor_name), CAMERA_DEV_NAME, id); + if (!strncmp(ldev->kobj.name, + sensor_name, sizeof(sensor_name))) { + info->mount_angle = + camera_data[id].module->mount_angle; + info->sensor_rotation = + camera_data[id].module->sensor_rotation; + info->sensor_facing = + camera_data[id].module->sensor_facing; + info->sensor_config_delay_num = + camera_data[id].module->sensor_config_delay_num; + memset(info->sensor_config_delay, 0, sizeof(info->sensor_config_delay)); + memcpy(info->sensor_config_delay, camera_data[id].module->sensor_config_delay, + sizeof(info->sensor_config_delay)); + info->temperature_check_skip_num = + camera_data[id].module->temperature_check_skip_num; + info->total_pixel_number_w = + camera_data[id].module->total_pixel_number_w; + info->total_pixel_number_h = + camera_data[id].module->total_pixel_number_h; + info->active_pixel_number_x = + camera_data[id].module->active_pixel_number_x; + info->active_pixel_number_y = + camera_data[id].module->active_pixel_number_y; + info->active_pixel_number_w = + camera_data[id].module->active_pixel_number_w; + info->active_pixel_number_h = + camera_data[id].module->active_pixel_number_h; + info->min_focus_distance = + camera_data[id].module->min_focus_distance; + info->hyper_focal_distance = + camera_data[id].module->hyper_focal_distance; + memset(info->diagonal_len, 0, + sizeof(info->diagonal_len)); + strlcpy(info->diagonal_len, + camera_data[id].module->diagonal_len, + sizeof(info->diagonal_len)); + memset(info->unit_cell_size_w, 0, + sizeof(info->unit_cell_size_w)); + strlcpy(info->unit_cell_size_w, + camera_data[id].module->unit_cell_size_w, + sizeof(info->unit_cell_size_w)); + memset(info->unit_cell_size_h, 0, + sizeof(info->unit_cell_size_h)); + strlcpy(info->unit_cell_size_h, + camera_data[id].module->unit_cell_size_h, + sizeof(info->unit_cell_size_h)); + memset(info->min_f_number, 0, + sizeof(info->min_f_number)); + strlcpy(info->min_f_number, + camera_data[id].module->min_f_number, + sizeof(info->min_f_number)); + memset(info->max_f_number, 0, + sizeof(info->max_f_number)); + strlcpy(info->max_f_number, + camera_data[id].module->max_f_number, + sizeof(info->max_f_number)); + info->min_focus_pos = + camera_data[id].module->min_focus_pos; + info->max_focus_pos = + camera_data[id].module->max_focus_pos; + info->min_focus_dac = + camera_data[id].module->min_focus_dac; + info->max_focus_dac = + camera_data[id].module->max_focus_dac; + info->focus_inf_range_offset = + camera_data[id].module->focus_inf_range_offset; + info->focus_macro_range_offset = + camera_data[id].module->focus_macro_range_offset; + info->focus_lens_stroke_inf_to_1m = + camera_data[id].module->focus_lens_stroke_inf_to_1m; + info->focus_lens_stroke_1m_to_macro = + camera_data[id].module->focus_lens_stroke_1m_to_macro; + info->focus_lens_stroke_inf_to_macro = + camera_data[id].module->focus_lens_stroke_inf_to_macro; + info->focus_calc_type = + camera_data[id].module->focus_calc_type; + info->focus_wob_time = + camera_data[id].module->focus_wob_time; + info->has_3a = + camera_data[id].module->has_3a; + info->has_focus_actuator = + camera_data[id].module->has_focus_actuator; + info->has_pdaf = + camera_data[id].module->has_pdaf; + info->has_rs = + camera_data[id].module->has_rs; + info->has_multi_output = + camera_data[id].module->has_multi_output; + info->has_super_slow = + camera_data[id].module->has_super_slow; + info->has_sub_sensor = + camera_data[id].module->has_sub_sensor; + info->has_aube = + camera_data[id].module->has_aube; + info->has_flicker_detector = + camera_data[id].module->has_flicker_detector; + info->has_hw_sof = + (camera_data[id].sof_gpio >= 0) ? 1 : 0; + info->has_hdr = + camera_data[id].module->has_hdr; + info->has_seamless_mode_change = + camera_data[id].module->has_seamless_mode_change; + info->has_gph = + camera_data[id].module->has_gph; + info->pdaf_free_area_num = + camera_data[id].module->pdaf_free_area_num; + info->pdaf_fixed_area_size_w = + camera_data[id].module->pdaf_fixed_area_size_w; + info->pdaf_fixed_area_size_h = + camera_data[id].module->pdaf_fixed_area_size_h; + info->pll_num = + camera_data[id].module->pll_num; + memset(info->pll, 0, sizeof(info->pll)); + memcpy(info->pll, camera_data[id].module->pll, + sizeof(info->pll)); + memset(info->eeprom, 0, sizeof(info->eeprom)); + memcpy(info->eeprom, camera_data[id].eeprom, + camera_data[id].eeprom_len); + info->eeprom_size = camera_data[id].eeprom_len; + info_len = sizeof(struct camera_read_info); + break; + } + } + return info_len; +} + +static ssize_t sony_camera_info_write(struct device *ldev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char sensor_name[CAPS_MAX_STR_LEN]; + int id = 0; + uint16_t info_len = 0; + struct camera_write_info *info = (struct camera_write_info *)buf; + + memset(sensor_name, 0, sizeof(sensor_name)); + for (id = 0; id < sensor_num; id++) { + snprintf(sensor_name, sizeof(sensor_name), CAMERA_DEV_NAME, id); + if (!strncmp(ldev->kobj.name, + sensor_name, sizeof(sensor_name))) { + camera_data[id].thermal_sensor_temp = info->sensor_temp; + camera_data[id].thermal_ret_val = 0; + info_len = sizeof(struct camera_write_info); + LOGD("%d thermal_sensor_temp[%d] = %d\n", __LINE__, id, + camera_data[id].thermal_sensor_temp); + } + } + return info_len; +} + +static struct device_attribute sony_camera_info_attributes[] = { + __ATTR(info, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP, + sony_camera_info_read, sony_camera_info_write), + __ATTR(info, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP, + sony_camera_info_read, sony_camera_info_write), +}; + +static int sony_camera_info_init(int id) +{ + int rc = 0; + + rc = dev_set_name(&camera_data[id].info_dev, + CAMERA_DEV_NAME, id); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto reg_fail; + } + rc = device_register(&camera_data[id].info_dev); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + goto reg_fail; + } + + rc = device_create_file(&camera_data[id].info_dev, + &sony_camera_info_attributes[id]); + if (rc < 0) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -ENODEV; + goto create_fail; + } + return 0; + +create_fail: + device_unregister(&camera_data[id].info_dev); +reg_fail: + return rc; +} + +static void sony_camera_info_deinit(void) +{ + int id = 0; + + for (id = 0; id < sensor_num; id++) { + device_remove_file(&camera_data[id].info_dev, + &sony_camera_info_attributes[id]); + device_unregister(&camera_data[id].info_dev); + } +} + +static int sony_eeprom_load(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint16_t i; + uint16_t len; + uint16_t id = sony_util_get_context(s_ctrl); + uint8_t *d = camera_data[id].eeprom; + + LOGI("load eeprom\n"); + + /* load eeprom */ + if (camera_info[id].eeprom_type == 0) { + for (i = 0; i < camera_info[id].eeprom_max_len; + i += I2C_MAX_DATA_LEN) { + uint8_t slave_addr = camera_info[id].eeprom_addr + + ((i & 0x0700) >> 7); + uint32_t offset = i & 0x00FF; + + rc = sony_util_cam_i2c_read( + &camera_data[id].s_ctrl, + slave_addr, + offset, MSM_CAMERA_I2C_BYTE_ADDR, + I2C_MAX_DATA_LEN, d + i); + if (rc < 0) { + LOGE("eeprom type %d i2c read fail %d\n", + camera_info[id].eeprom_type, rc); + camera_data[id].eeprom_len = 0; + goto exit; + } + } + len = i; + } else if (camera_info[id].eeprom_type == 2) { + len = camera_info[id].eeprom_max_len; + rc = sony_util_cam_i2c_read( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0, MSM_CAMERA_I2C_WORD_ADDR, + camera_info[id].eeprom_max_len, d); + if (rc < 0) { + LOGE("eeprom type %d i2c read fail %d\n", + camera_info[id].eeprom_type, rc); + camera_data[id].eeprom_len = 0; + goto exit; + } + } else { + len = camera_info[id].eeprom_max_len; + + d[0] = 0x03; + d[1] = 0x25; + rc = sony_util_cam_i2c_write( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x0010, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + + d[0] = 0x08; + d[1] = 0x00; + rc = sony_util_cam_i2c_write( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x0012, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + + i = 0; + do { + msleep(20); + i++; + rc = sony_util_cam_i2c_read( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x0014, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + } while ((d[0] & 0x80) && i < 100); + + if (i >= 100) { + rc = -ENODEV; + goto exit; + } + + d[0] = 0x45; + d[1] = 0x04; + rc = sony_util_cam_i2c_write( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x0018, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + + i = 0; + do { + msleep(20); + i++; + rc = sony_util_cam_i2c_read( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x0018, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + } while ((d[1] & 0x40) && i < 100); + + if (i >= 100) { + rc = -ENODEV; + goto exit; + } + + d[0] = 0x05; + d[1] = 0x20; + rc = sony_util_cam_i2c_write( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x001A, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + + d[0] = 0x05; + d[1] = 0x64; + rc = sony_util_cam_i2c_write( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x001A, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + + rc = sony_util_cam_i2c_read(&camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x0000, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) { + LOGE("i2c read faile\n"); + goto exit; + } + + if (((uint16_t)d[0] << 8 | d[1]) == SENSOR_ID_MT9M114) { + d[0] = 0x00; + d[1] = 0x55; + rc = sony_util_cam_i2c_write( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x3052, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + + d[0] = 0x00; + d[1] = 0x10; + rc = sony_util_cam_i2c_write( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x3050, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + + i = 0; + do { + msleep(20); + i++; + rc = sony_util_cam_i2c_read( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x3050, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + } while (!(d[1] & 0x20) && i < 100); + + if (i >= 100) { + rc = -ENODEV; + goto exit; + } + + rc = sony_util_cam_i2c_read( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x313A, MSM_CAMERA_I2C_WORD_ADDR, 2, d + 8); + if (rc < 0) + goto exit; + + rc = sony_util_cam_i2c_read( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x313C, MSM_CAMERA_I2C_WORD_ADDR, 2, d + 10); + if (rc < 0) + goto exit; + + if ((d[8] & 0xC0) == 0x00) + memcpy(d, MODULE_STW01BM0, SENSOR_NAME_LEN); + else + memcpy(d, MODULE_APT01BM0, SENSOR_NAME_LEN); + } else if (((uint16_t)d[0] << 8 | d[1]) == SENSOR_ID_MT9V115) { + rc = sony_util_cam_i2c_read( + &camera_data[id].s_ctrl, + camera_info[id].eeprom_addr, + 0x001A, MSM_CAMERA_I2C_WORD_ADDR, 2, d); + if (rc < 0) + goto exit; + + if ((d[0] & 0xF0) == 0xB0) + memcpy(d, MODULE_APT00YP1, 8); + else if ((d[0] & 0xF0) == 0xE0 || (d[0] & 0xF0) == 0x00) + memcpy(d, MODULE_STW00YP1, 8); + else { + LOGE("%s ModuleID is unknown\n", __func__); + memcpy(d, MODULE_APT00YP1, 8); + } + } else { + LOGE("%s Wrong camera module.\n", __func__); + } + } + + + /* identify sensor module */ + for (i = 1; i < camera_info[id].modules_num; i++) { + if (!strncmp(camera_info[id].modules[i].name, + camera_data[id].eeprom, + SENSOR_NAME_LEN)) { + camera_data[id].module = + &camera_info[id].modules[i]; + LOGD("detected sensor module name\n"); + + break; + } + } + + if (camera_data[id].module) + camera_data[id].eeprom_len = len; + else { + LOGE("Module name not recognized. Force name.\n"); + + camera_data[id].module = &camera_info[id].modules[0]; + + for (i = 1; i < camera_info[id].modules_num; i++) { + if (!strncmp(camera_info[id].modules[i].name, + camera_info[id].default_module_name, + SENSOR_NAME_LEN)) { + camera_data[id].module + = &camera_info[id].modules[i]; + LOGD("detected sensor Force name\n"); + break; + } + } + + memcpy(d, camera_info[id].default_module_name, SENSOR_NAME_LEN); + camera_data[id].eeprom_len = len; + } + + LOGI("MODULE NAME: len=%d, name=%c%c%c%c%c%c%c%c\n", + len, d[0], d[1], d[2], d[3], + d[4], d[5], d[6], d[7]); + +exit: + return rc; +} + +static int32_t sony_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint16_t id = sony_util_get_context(s_ctrl); + + if (camera_data[id].probe_done == false) { + /* force EEPROM read speed to 400KHz, it will be overwritten + * to the speed defined in dtsi when probe is done */ + s_ctrl->sensor_i2c_client->cci_client->i2c_freq_mode = + EEPROM_READ_FREQ_MODE; + rc = sony_eeprom_load(s_ctrl); + if (rc < 0) + LOGE("eeprom load fail\n"); + } + return rc; +} + +static int sony_sensor_pinctrl_init(struct msm_camera_power_ctrl_t *ctrl) +{ + struct msm_pinctrl_info *sensor_pctrl = NULL; + + sensor_pctrl = &ctrl->pinctrl_info; + sensor_pctrl->pinctrl = devm_pinctrl_get(ctrl->dev); + if (IS_ERR_OR_NULL(sensor_pctrl->pinctrl)) { + pr_err("%s:%d Getting pinctrl handle failed\n", + __func__, __LINE__); + return -EINVAL; + } + sensor_pctrl->gpio_state_active = + pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_active)) { + pr_err("%s:%d Failed to get the active state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + sensor_pctrl->gpio_state_suspend + = pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_suspend)) { + pr_err("%s:%d Failed to get the suspend state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + +static void sony_sensor_send_event(struct v4l2_subdev *sd, + uint32_t event_type, struct msm_sensor_event_data *event_data) +{ + struct v4l2_event sensor_event; +#ifdef CONFIG_COMPAT + struct msm_sensor_event_data32 *event_data32 = NULL; +#endif + memset(&sensor_event, 0, sizeof(struct v4l2_event)); + sensor_event.id = 0; + sensor_event.type = event_type; +#ifdef CONFIG_COMPAT + event_data32 = + (struct msm_sensor_event_data32 *)(&sensor_event.u.data[0]); + event_data32->mono_timestamp.tv_sec = + event_data->mono_timestamp.tv_sec; + event_data32->mono_timestamp.tv_usec = + event_data->mono_timestamp.tv_usec; + event_data32->sof_count = event_data->sof_count; +#else + memcpy(&sensor_event.u.data[0], event_data, + sizeof(struct msm_sensor_event_data)); +#endif + v4l2_event_queue(sd->devnode, &sensor_event); +} + +static irqreturn_t sony_sensor_sof_irq(int irq, void *handle) +{ + struct msm_sensor_event_data event_data; + struct msm_sensor_ctrl_t *s_ctrl = (struct msm_sensor_ctrl_t *)handle; + struct timespec ts; + + ktime_get_ts(&ts); + s_ctrl->sof_count++; + if (s_ctrl->sof_count > 0xFFFFFFF0) + s_ctrl->sof_count = 1; + + memset(&event_data, 0, sizeof(event_data)); + event_data.sof_count = s_ctrl->sof_count; + event_data.mono_timestamp.tv_sec = ts.tv_sec; + event_data.mono_timestamp.tv_usec = ts.tv_nsec / 1000; + sony_sensor_send_event(&s_ctrl->msm_sd.sd, + SENSOR_EVENT_SOF, &event_data); + return IRQ_HANDLED; +} + +static int sony_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *data = s_ctrl->sensordata; + struct task_struct *task = NULL; + uint16_t id = sony_util_get_context(s_ctrl); + + mutex_lock(&af_standby_mutex); + task = af_task; + af_task = NULL; + mutex_unlock(&af_standby_mutex); + if (task) + kthread_stop(task); + mutex_lock(&af_standby_mutex); + + LOGD("%s: %d\n", __func__, __LINE__); + rc = sony_util_gpio_init(s_ctrl); + if (rc < 0) { + LOGE("%s: gpio_init failed\n", __func__); + goto exit; + } + rc = sony_sensor_pinctrl_init(&data->power_info); + if (rc < 0) { + pr_err("%s:%d Initialization of pinctrl failed\n", + __func__, __LINE__); + data->power_info.cam_pinctrl_status = 0; + } else { + data->power_info.cam_pinctrl_status = 1; + } + if (data->power_info.cam_pinctrl_status) { + rc = pinctrl_select_state(data->power_info.pinctrl_info.pinctrl, + data->power_info.pinctrl_info.gpio_state_active); + if (rc) + pr_err("%s:%d cannot set pin to active state", + __func__, __LINE__); + } + LOGE("%s: id = %d, sof_gpio %d %p\n", __func__, id, camera_data[id].sof_gpio, dev_name(camera_data[id].d)); + if (camera_data[id].sof_gpio >= 0) { + camera_data[id].sof_irq = gpio_to_irq(camera_data[id].sof_gpio); + rc = request_threaded_irq(camera_data[id].sof_irq, NULL, + sony_sensor_sof_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(camera_data[id].d), s_ctrl); + if (rc) { + LOGE("Failed to request sof irq\n"); + goto exit; + } + } + + rc = sony_util_power_ctrl(s_ctrl, &camera_data[id], true); + if (rc < 0) { + LOGE("power_up fail\n"); + goto exit; + } + + rc = sony_util_cci_init(s_ctrl->sensor_i2c_client); + if (rc < 0) { + LOGE("%s cci_init failed\n", __func__); + goto exit; + } + + if (data->power_info.i2c_conf && + data->power_info.i2c_conf->use_i2c_mux) + sony_util_i2c_mux_enable( + data->power_info.i2c_conf); + + af_task = kthread_run(sony_util_sub_camera_af_standby_task, + s_ctrl, "sony_util_task"); + if (!af_task) { + LOGE("%s standby sub camera af kthread_run failed\n", + __func__); + goto exit; + } + + if (s_ctrl->func_tbl->sensor_match_id) + rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl); + camera_data[id].power_up_done = true; + camera_data[id].thermal_ret_val = -EINVAL; + +#if defined(CONFIG_LEDS_QPNP_RGB_SCALE) && (CONFIG_FRONT_CAMERA_LED_SCALE > 0) + if (s_ctrl->sensordata->sensor_info->position == 1) { + qpnp_led_set_rgb_scale(CONFIG_FRONT_CAMERA_LED_SCALE); + } +#endif + +exit: + mutex_unlock(&af_standby_mutex); + + return rc; +} + +static int sony_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *data = s_ctrl->sensordata; + struct task_struct *task = NULL; + uint16_t id = sony_util_get_context(s_ctrl); + + mutex_lock(&af_standby_mutex); + task = af_task; + af_task = NULL; + mutex_unlock(&af_standby_mutex); + if (task) + kthread_stop(task); + mutex_lock(&af_standby_mutex); + + rc = sony_util_power_ctrl(s_ctrl, &camera_data[id], false); + if (rc < 0) + LOGE("power_down fail\n"); + + if (data->power_info.i2c_conf && + data->power_info.i2c_conf->use_i2c_mux) + sony_util_i2c_mux_disable( + data->power_info.i2c_conf); + + rc = sony_util_cci_deinit(s_ctrl->sensor_i2c_client); + if (rc < 0) + LOGE("%s cci_deinit failed\n", __func__); + + LOGE("%s: sof_gpio %d\n", __func__, camera_data[id].sof_gpio); + if (camera_data[id].sof_gpio >= 0) + free_irq(camera_data[id].sof_irq, s_ctrl); + + if (data->power_info.cam_pinctrl_status) { + rc = pinctrl_select_state(data->power_info.pinctrl_info.pinctrl, + data->power_info.pinctrl_info.gpio_state_suspend); + if (rc) + pr_err("%s:%d cannot set pin to suspend state", + __func__, __LINE__); + } + data->power_info.cam_pinctrl_status = 0; + + rc = sony_util_gpio_deinit(s_ctrl); + if (rc < 0) + LOGE("%s: gpio_deinit failed\n", __func__); + camera_data[id].power_up_done = false; + mutex_unlock(&af_standby_mutex); + camera_data[id].thermal_ret_val = -ENODEV; + +#if defined(CONFIG_LEDS_QPNP_RGB_SCALE) && (CONFIG_FRONT_CAMERA_LED_SCALE > 0) + if (s_ctrl->sensordata->sensor_info->position == 1) { + qpnp_led_set_rgb_scale(100); + } +#endif + + return rc; +} + +static struct v4l2_subdev_info sony_sensor_subdev_info[] = { + { + .code = 0x00, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, + { + .code = 0x00, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static struct msm_camera_i2c_client sony_sensor_i2c_client[] = { + { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + }, + { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, + }, +}; + +static const struct of_device_id sony_camera_0_dt_match[] = { + { + .compatible = "qcom,sony_camera_0", + .data = &camera_data[0].s_ctrl + }, + { + }, +}; + +static const struct of_device_id sony_camera_1_dt_match[] = { + { + .compatible = "qcom,sony_camera_1", + .data = &camera_data[1].s_ctrl + }, + { + }, +}; + +MODULE_DEVICE_TABLE(of, sony_camera_0_dt_match); +MODULE_DEVICE_TABLE(of, sony_camera_1_dt_match); + +static struct platform_driver sony_sensor_platform_driver[] = { + { + .driver = { + .name = "qcom,sony_camera_0", + .owner = THIS_MODULE, + .of_match_table = sony_camera_0_dt_match, + }, + }, + { + .driver = { + .name = "qcom,sony_camera_1", + .owner = THIS_MODULE, + .of_match_table = sony_camera_1_dt_match, + }, + }, +}; + +static int sony_camera_platform_probe(struct platform_device *pdev) +{ + int rc = 0; + const struct of_device_id *match; + uint16_t id = 0; + struct msm_sensor_ctrl_t *s_ctrl = NULL; + struct msm_sensor_info_t *sensor_init_params; + + mutex_lock(&af_standby_mutex); + match = of_match_device(sony_camera_0_dt_match, &pdev->dev); + if (!match && 1 < sensor_num) { + match = of_match_device(sony_camera_1_dt_match, &pdev->dev); + id = 1; + } + if (!match) { + LOGE("of_match_device fail\n"); + rc = -EFAULT; + mutex_unlock(&af_standby_mutex); + goto fail; + } + camera_data[id].d = &pdev->dev; + camera_data[id].probe_done = false; + + rc = sony_util_camera_info_init(pdev, id); + if (rc < 0) { + LOGE("%s sony_util_camera_info_init failed %d\n", + __func__, __LINE__); + mutex_unlock(&af_standby_mutex); + goto fail; + } + + s_ctrl = (struct msm_sensor_ctrl_t *)match->data; + s_ctrl->sensor_v4l2_subdev_info->code = camera_info[id].subdev_code; + + af_task = NULL; + mutex_unlock(&af_standby_mutex); + + rc = msm_sensor_platform_probe(pdev, match->data); + if (rc < 0) { + LOGE("%s msm_sensor_platform_probe failed %d\n", + __func__, __LINE__); + goto fail; + } + + s_ctrl->sensor_i2c_client->cci_client->i2c_freq_mode = + camera_info[id].modules[id].i2c_freq_mode; + sensor_init_params = s_ctrl->sensordata->sensor_info; + mutex_lock(&af_standby_mutex); + camera_data[id].probe_done = true; + mutex_unlock(&af_standby_mutex); + LOGI("camera %d probe ok\n", id); + + return 0; +fail: + return rc; +} + +static int __init sony_sensor_init_module(void) +{ + int rc = 0; + uint16_t i; + uint16_t probe_count = 0; + char *thermal_name[2] = {CAMERA_THERMAL_NAME_0, CAMERA_THERMAL_NAME_1}; + + sensor_num = ARRAY_SIZE(sony_sensor_platform_driver); + + camera_info = kzalloc(sizeof(struct sony_camera_info) * sensor_num, + GFP_KERNEL); + if (!camera_info) { + LOGE("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto fail_alloc; + } + + for (i = 0; i < sensor_num; i++) { + rc = platform_driver_probe(&sony_sensor_platform_driver[i], + sony_camera_platform_probe); + if (rc < 0) { + LOGE("%s platform_driver_probe (%u) %d\n", + __func__, i, __LINE__); + continue; + } + rc = sony_camera_info_init(i); + if (rc < 0) { + LOGE("%s sony_camera_info_init (%u) %d\n", + __func__, i, __LINE__); + platform_driver_unregister( + &sony_sensor_platform_driver[i]); + continue; + } + camera_data[i].thermal_zone_dev = + thermal_zone_device_register(thermal_name[i], + 0, 0, 0, &sony_camera_thermal_ops, 0, 0, 0); + if (IS_ERR(camera_data[i].thermal_zone_dev)) { + LOGE("%s thermal_zone_device_register (%u) %d\n", + __func__, i, __LINE__); + rc = PTR_ERR(camera_data[i].thermal_zone_dev); + platform_driver_unregister( + &sony_sensor_platform_driver[i]); + continue; + } + probe_count++; + } + + if (!probe_count) { + LOGE("%s platform_driver_probe (%u) %d\n", + __func__, probe_count, __LINE__); + goto fail_probe; + } + + return 0; +fail_probe: + kfree(camera_info); + camera_info = NULL; +fail_alloc: + return rc; +} + +static void __exit sony_sensor_exit_module(void) +{ + uint16_t i; + + sony_camera_info_deinit(); + for (i = 0; i < sensor_num; i++) { + platform_driver_unregister(&sony_sensor_platform_driver[i]); + msm_sensor_free_sensor_data(&camera_data[i].s_ctrl); + sony_util_camera_info_deinit(i); + thermal_zone_device_unregister(camera_data[i].thermal_zone_dev); + } + kfree(camera_info); + camera_info = NULL; +} + +static struct msm_sensor_fn_t sony_sensor_func_tbl = { +#ifdef CONFIG_COMPAT + .sensor_config32 = msm_sensor_config32, +#endif + .sensor_config = msm_sensor_config, + .sensor_power_up = sony_sensor_power_up, + .sensor_power_down = sony_sensor_power_down, + .sensor_match_id = sony_sensor_match_id, +}; + +static struct sony_camera_data camera_data[] = { + { + .s_ctrl = { + .sensor_i2c_client = &sony_sensor_i2c_client[0], + .power_setting_array.power_setting = sony_power_setting, + .power_setting_array.size = + ARRAY_SIZE(sony_power_setting), + .msm_sensor_mutex = &sensor_mutex, + .sensor_v4l2_subdev_info = &sony_sensor_subdev_info[0], + .sensor_v4l2_subdev_info_size = + ARRAY_SIZE(sony_sensor_subdev_info), + .func_tbl = &sony_sensor_func_tbl, + }, + .thermal_sensor_temp = 0, + .thermal_ret_val = -ENODEV, + .sof_irq = 0, + .sof_gpio = -1, + }, + { + .s_ctrl = { + .sensor_i2c_client = &sony_sensor_i2c_client[1], + .power_setting_array.power_setting = sony_power_setting, + .power_setting_array.size = + ARRAY_SIZE(sony_power_setting), + .msm_sensor_mutex = &sensor_mutex, + .sensor_v4l2_subdev_info = + &sony_sensor_subdev_info[1], + .sensor_v4l2_subdev_info_size = + ARRAY_SIZE(sony_sensor_subdev_info), + .func_tbl = &sony_sensor_func_tbl, + }, + .thermal_sensor_temp = 0, + .thermal_ret_val = -ENODEV, + .sof_irq = 0, + .sof_gpio = -1, + }, +}; + +module_init(sony_sensor_init_module); +module_exit(sony_sensor_exit_module); + +MODULE_DESCRIPTION("SONY V4L2 camera sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2/sensor/sony_camera_v4l2.h b/drivers/media/platform/msm/camera_v2/sensor/sony_camera_v4l2.h new file mode 100644 index 0000000000000000000000000000000000000000..ff635f0a29520b4efbc2f694e301bbf8242009c7 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/sony_camera_v4l2.h @@ -0,0 +1,116 @@ +/* drivers/media/platform/msm/camera_v2/sensor/sony_camera_v4l2.h + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SONY_CAMERA_V4L2_H +#define __LINUX_SONY_CAMERA_V4L2_H + +#ifdef __KERNEL__ + +#define MAX_CONFIG_DELAY_NUM 20 +#define MAX_PLL_NUM 30 + +enum sony_camera_cmd { + SONY_CAM_VDIG, + SONY_CAM_VIO, + SONY_CAM_VANA, + SONY_CAM_VAF, + SONY_GPIO_AF, + SONY_GPIO_RESET, + SONY_CAM_VDIG_GPIO, + SONY_CAM_VIO_GPIO, + SONY_CAM_VANA_GPIO, + SONY_CAM_VAF_GPIO, + SONY_CAM_CLK, + SONY_I2C_WRITE, + EXIT, +}; + +struct sony_camera_seq { + enum sony_camera_cmd cmd; + int val1; + int val2; + int wait; +}; + +struct sony_camera_module { + const char *name; + struct sony_camera_seq *seq_on; + struct sony_camera_seq *seq_off; + uint32_t mount_angle; + uint32_t sensor_rotation; + uint32_t sensor_facing; + uint32_t sensor_config_delay_num; + uint32_t sensor_config_delay[MAX_CONFIG_DELAY_NUM]; + uint32_t temperature_check_skip_num; + uint32_t total_pixel_number_w; + uint32_t total_pixel_number_h; + uint32_t active_pixel_number_x; + uint32_t active_pixel_number_y; + uint32_t active_pixel_number_w; + uint32_t active_pixel_number_h; + uint32_t min_focus_distance; + uint32_t hyper_focal_distance; + const char *diagonal_len; + const char *unit_cell_size_w; + const char *unit_cell_size_h; + const char *min_f_number; + const char *max_f_number; + uint32_t min_focus_pos; + uint32_t max_focus_pos; + uint32_t min_focus_dac; + uint32_t max_focus_dac; + uint32_t focus_inf_range_offset; + uint32_t focus_macro_range_offset; + uint32_t focus_lens_stroke_inf_to_1m; + uint32_t focus_lens_stroke_1m_to_macro; + uint32_t focus_lens_stroke_inf_to_macro; + uint32_t focus_calc_type; + uint32_t focus_wob_time; + uint32_t has_3a; + uint32_t has_focus_actuator; + uint32_t need_standby_af; + uint32_t i2c_freq_mode; + uint32_t has_pdaf; + uint32_t has_rs; + uint32_t has_multi_output; + uint32_t has_super_slow; + uint32_t has_sub_sensor; + uint32_t has_aube; + uint32_t has_flicker_detector; + uint32_t has_hdr; + uint32_t has_seamless_mode_change; + uint32_t has_gph; + uint32_t pdaf_free_area_num; + uint32_t pdaf_fixed_area_size_w; + uint32_t pdaf_fixed_area_size_h; + uint32_t pll_num; + uint32_t pll[MAX_PLL_NUM]; + uint32_t reserved; +}; + +struct sony_camera_info { + uint16_t i2c_addr; + uint16_t eeprom_addr; + int eeprom_type; + uint16_t eeprom_max_len; + int gpio_af; + int subdev_code; + struct sony_camera_module *modules; + int modules_num; + const char *default_module_name; +}; + +#endif +#endif diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c index 9f3e2cc3a72f5dc1d479ee53726b9bb287fce80f..2d229689314088f10d9f4f089761001a35e431e0 100644 --- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c @@ -523,17 +523,13 @@ static ssize_t mpq_sdmx_log_level_write(struct file *fp, int level; struct mpq_demux *mpq_demux = fp->private_data; - if (count == 0 || count >= 16) + if (count >= 16) return -EINVAL; - memset(user_str, '\0', sizeof(user_str)); - - ret_count = simple_write_to_buffer(user_str, 15, position, user_buffer, + ret_count = simple_write_to_buffer(user_str, 16, position, user_buffer, count); if (ret_count < 0) return ret_count; - else if (ret_count == 0) - return -EINVAL; ret = kstrtoint(user_str, 0, &level); if (ret) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index 422c7a590a455cf49e92b5cdf04d2e944c96706e..abf20aef12567eec57c34a9d40b65afba5cdf1ad 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -2003,10 +2003,8 @@ static void sde_rotator_cancel_request(struct sde_rot_mgr *mgr, sde_rot_mgr_unlock(mgr); for (i = req->count - 1; i >= 0; i--) { entry = req->entries + i; - if (entry->commitq) - flush_kthread_worker(&entry->commitq->rot_kw); - if (entry->doneq) - flush_kthread_worker(&entry->doneq->rot_kw); + flush_kthread_worker(&entry->commitq->rot_kw); + flush_kthread_worker(&entry->doneq->rot_kw); } sde_rot_mgr_lock(mgr); SDEROT_DBG("cancel work done\n"); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c index 10f72a2155db9eda8ea3d7130b706bc5765f452b..acb697946e18eed11441a81878a09d5504b8d849 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -814,9 +814,6 @@ static void sde_hw_rotator_setup_wbengine(struct sde_hw_rotator_context *ctx, bw /= TRAFFIC_SHAPE_CLKTICK_12MS; if (bw > 0xFF) bw = 0xFF; - else if (bw == 0) - bw = 1; - SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT, BIT(31) | bw); SDEROT_DBG("Enable ROT_WB Traffic Shaper:%d\n", bw); diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index e81162f3c4ad21f14ad4124b9c1d4c866b9b345e..de5a2dececdf769c9c18bb6746ad433581bec28f 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -456,14 +456,13 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) struct device *dev; int nr = BASE_DEVICE_NUMBER; - if (!vidc_driver) { - dprintk(VIDC_ERR, "Invalid vidc driver\n"); - return -EINVAL; - } - core = kzalloc(sizeof(*core), GFP_KERNEL); - if (!core) - return -ENOMEM; + if (!core || !vidc_driver) { + dprintk(VIDC_ERR, + "Failed to allocate memory for device core\n"); + rc = -ENOMEM; + goto err_no_mem; + } dev_set_drvdata(&pdev->dev, core); rc = msm_vidc_initialize_core(pdev, core); @@ -629,6 +628,7 @@ err_v4l2_register: err_core_init: dev_set_drvdata(&pdev->dev, NULL); kfree(core); +err_no_mem: return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 0a008447fa13f5aaf5e2e79a918b36a62a3f6fab..28a4006b480cd55ef42bc696f9bf9db35d14c87b 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -23,7 +23,6 @@ #define MSM_VDEC_DVC_NAME "msm_vdec_8974" #define MIN_NUM_OUTPUT_BUFFERS 4 -#define MIN_NUM_OUTPUT_BUFFERS_VP9 6 #define MIN_NUM_CAPTURE_BUFFERS 6 #define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS 1 #define MAX_NUM_OUTPUT_BUFFERS VB2_MAX_FRAME @@ -848,14 +847,6 @@ int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i) return -EINVAL; } dprintk(VIDC_DBG, "Calling streamoff\n"); - - if (!inst->in_reconfig) { - rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); - if (rc) - dprintk(VIDC_ERR, - "Failed to move inst: %pK to res done state\n", inst); - } - mutex_lock(&q->lock); rc = vb2_streamoff(&q->vb2_bufq, i); mutex_unlock(&q->lock); @@ -1469,17 +1460,6 @@ static int msm_vdec_queue_setup(struct vb2_queue *q, if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS || *num_buffers > MAX_NUM_OUTPUT_BUFFERS) *num_buffers = MIN_NUM_OUTPUT_BUFFERS; - /* - * Increase input buffer count to 6 as for some - * vp9 clips which have superframes with more - * than 4 subframes requires more than 4 - * reference frames to decode. - */ - if (inst->fmts[OUTPUT_PORT].fourcc == - V4L2_PIX_FMT_VP9 && - *num_buffers < MIN_NUM_OUTPUT_BUFFERS_VP9) - *num_buffers = MIN_NUM_OUTPUT_BUFFERS_VP9; - for (i = 0; i < *num_planes; i++) { sizes[i] = get_frame_size(inst, &inst->fmts[OUTPUT_PORT], q->type, i); @@ -1511,7 +1491,6 @@ static int msm_vdec_queue_setup(struct vb2_queue *q, rc = -EINVAL; break; } - msm_dcvs_try_enable(inst); /* Pretend as if FW itself is asking for * additional buffers. @@ -1591,10 +1570,9 @@ exit: return rc; } -static int set_max_internal_buffers_size(struct msm_vidc_inst *inst) +static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst) { int rc = 0; - struct msm_vidc_list *buf_list = &inst->scratchbufs; struct { enum hal_buffer type; struct hal_buffer_requirements *req; @@ -1602,17 +1580,13 @@ static int set_max_internal_buffers_size(struct msm_vidc_inst *inst) } internal_buffers[] = { { HAL_BUFFER_INTERNAL_SCRATCH, NULL, 0}, { HAL_BUFFER_INTERNAL_SCRATCH_1, NULL, 0}, + { HAL_BUFFER_INTERNAL_SCRATCH_2, NULL, 0}, + { HAL_BUFFER_INTERNAL_PERSIST, NULL, 0}, + { HAL_BUFFER_INTERNAL_PERSIST_1, NULL, 0}, }; struct hal_frame_size frame_sz; int i; - mutex_lock(&buf_list->lock); - if (!list_empty(&buf_list->list)) { - dprintk(VIDC_DBG, "Scratch list already has allocated buf\n"); - mutex_unlock(&buf_list->lock); - return 0; - } - mutex_unlock(&buf_list->lock); frame_sz.buffer_type = HAL_BUFFER_INPUT; frame_sz.width = inst->capability.width.max; @@ -1638,15 +1612,6 @@ static int set_max_internal_buffers_size(struct msm_vidc_inst *inst) get_buff_req_buffer(inst, internal_buffers[i].type); internal_buffers[i].size = internal_buffers[i].req ? internal_buffers[i].req->buffer_size : 0; - - rc = allocate_and_set_internal_bufs(inst, - internal_buffers[i].req, - &inst->scratchbufs, false); - if (rc) - goto alloc_fail; - dprintk(VIDC_DBG, - "Allocated scratch type : %d size to : %zd\n", - internal_buffers[i].type, internal_buffers[i].size); } frame_sz.buffer_type = HAL_BUFFER_INPUT; @@ -1659,18 +1624,25 @@ static int set_max_internal_buffers_size(struct msm_vidc_inst *inst) dprintk(VIDC_ERR, "%s Failed to get back old buf req, %d\n", __func__, rc); - goto alloc_fail; + return rc; } + dprintk(VIDC_DBG, "Old buffer reqs, buffer type = %d width = %d, height = %d\n", frame_sz.buffer_type, frame_sz.width, frame_sz.height); + for (i = 0; i < ARRAY_SIZE(internal_buffers); i++) { + if (internal_buffers[i].req) { + internal_buffers[i].req->buffer_size = + internal_buffers[i].size; + dprintk(VIDC_DBG, + "Changing buffer type : %d size to : %zd\n", + internal_buffers[i].type, + internal_buffers[i].size); + } + } return 0; - -alloc_fail: - msm_comm_release_scratch_buffers(inst, false); - return rc; } static inline int start_streaming(struct msm_vidc_inst *inst) @@ -1681,7 +1653,6 @@ static inline int start_streaming(struct msm_vidc_inst *inst) struct hal_buffer_size_minimum b; unsigned int buffer_size; struct msm_vidc_format *fmt = NULL; - bool max_internal_buf = false; fmt = &inst->fmts[CAPTURE_PORT]; buffer_size = fmt->get_frame_size(0, @@ -1705,9 +1676,8 @@ static inline int start_streaming(struct msm_vidc_inst *inst) dprintk(VIDC_ERR, "H/w scaling is not in valid range\n"); return -EINVAL; } - max_internal_buf = (inst->flags & VIDC_SECURE) && !slave_side_cp - && (inst->session_type == MSM_VIDC_DECODER); - if (max_internal_buf) { + if ((inst->flags & VIDC_SECURE) && !inst->in_reconfig && + !slave_side_cp) { rc = set_max_internal_buffers_size(inst); if (rc) { dprintk(VIDC_ERR, @@ -1716,7 +1686,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst) goto fail_start; } } - rc = msm_comm_set_scratch_buffers(inst, max_internal_buf); + rc = msm_comm_set_scratch_buffers(inst); if (rc) { dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc); diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 947ade9c99edc243ca0839355e182f1ea7b1e68c..c5816511e0563413829bff8935325d671b8a6f21 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1868,7 +1868,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst) "Failed to get Buffer Requirements : %d\n", rc); goto fail_start; } - rc = msm_comm_set_scratch_buffers(inst, false); + rc = msm_comm_set_scratch_buffers(inst); if (rc) { dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc); goto fail_start; @@ -4620,12 +4620,6 @@ int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i) return -EINVAL; } dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i); - - rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); - if (rc) - dprintk(VIDC_ERR, - "Failed to move inst: %pK to res done state\n", inst); - mutex_lock(&q->lock); rc = vb2_streamoff(&q->vb2_bufq, i); mutex_unlock(&q->lock); diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 3677bb6e32e6494682d4d9146cf137eef669cd55..7321e7cd0a3e9b3c225e4bd6579b056253979ab7 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -533,18 +533,11 @@ static inline void save_v4l2_buffer(struct v4l2_buffer *b, static int __map_and_update_binfo(struct msm_vidc_inst *inst, struct buffer_info *binfo, - struct v4l2_buffer *b, u32 i) + struct v4l2_buffer *b, int i) { int rc = 0; struct msm_smem *same_fd_handle = NULL; - if (i >= VIDEO_MAX_PLANES) { - dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n", - i, VIDEO_MAX_PLANES); - rc = -EINVAL; - goto exit; - } - same_fd_handle = get_same_fd_buffer( inst, b->m.planes[i].reserved[0]); @@ -557,7 +550,7 @@ static int __map_and_update_binfo(struct msm_vidc_inst *inst, binfo->handle[i] = map_buffer(inst, &b->m.planes[i], get_hal_buffer_type(inst, b)); if (!binfo->handle[i]) - return -EINVAL; + rc = -EINVAL; binfo->mapped[i] = true; binfo->device_addr[i] = binfo->handle[i]->device_addr + @@ -565,7 +558,6 @@ static int __map_and_update_binfo(struct msm_vidc_inst *inst, b->m.planes[i].m.userptr = binfo->device_addr[i]; } -exit: return rc; } @@ -573,8 +565,7 @@ static int __handle_fw_referenced_buffers(struct msm_vidc_inst *inst, struct buffer_info *binfo, struct v4l2_buffer *b) { - int rc = 0; - u32 i = 0; + int i = 0, rc = 0; if (EXTRADATA_IDX(b->length)) { i = EXTRADATA_IDX(b->length); @@ -592,8 +583,8 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) { struct buffer_info *binfo = NULL; struct buffer_info *temp = NULL, *iterator = NULL; - int plane = 0, rc = 0; - u32 i = 0; + int plane = 0; + int i = 0, rc = 0; if (!b || !inst) { dprintk(VIDC_ERR, "%s: invalid input\n", __func__); @@ -679,13 +670,13 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) rc = __map_and_update_binfo(inst, binfo, b, i); if (rc) - goto map_err; + goto exit; /* We maintain one ref count for all planes*/ if (!i && is_dynamic_output_buffer_mode(b, inst)) { rc = buf_ref_get(inst, binfo); if (rc < 0) - goto map_err; + goto exit; } dprintk(VIDC_DBG, "%s: [MAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n", @@ -699,14 +690,10 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) mutex_unlock(&inst->registeredbufs.lock); return 0; -map_err: - if (binfo->handle[0] && binfo->mapped[0]) - msm_comm_smem_free(inst, binfo->handle[0]); exit: kfree(binfo); return rc; } - int unmap_and_deregister_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 4cb8f92c4e389edbd2bb50c1bcb404f74c5b3341..f85fe6fd3867b0fafac069d3e3a2b8acf0fe59af 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1179,7 +1179,7 @@ static void handle_event_change(enum hal_command_response cmd, void *data) __func__, inst, &event_notify->packet_buffer, &event_notify->extra_data_buffer); - if (inst->state >= MSM_VIDC_STOP || + if (inst->state == MSM_VIDC_CORE_INVALID || inst->core->state == VIDC_CORE_INVALID) { dprintk(VIDC_DBG, "Event release buf ref received in invalid state - discard\n"); @@ -3342,9 +3342,9 @@ static bool reuse_internal_buffers(struct msm_vidc_inst *inst, return reused; } -int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, +static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, struct hal_buffer_requirements *internal_bufreq, - struct msm_vidc_list *buf_list, bool set_on_fw) + struct msm_vidc_list *buf_list) { struct msm_smem *handle; struct internal_buf *binfo; @@ -3381,13 +3381,11 @@ int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, binfo->handle = handle; binfo->buffer_type = internal_bufreq->buffer_type; - if (set_on_fw) { - rc = set_internal_buf_on_fw(inst, - internal_bufreq->buffer_type, - handle, false); - if (rc) - goto fail_set_buffers; - } + rc = set_internal_buf_on_fw(inst, internal_bufreq->buffer_type, + handle, false); + if (rc) + goto fail_set_buffers; + mutex_lock(&buf_list->lock); list_add_tail(&binfo->list, &buf_list->list); mutex_unlock(&buf_list->lock); @@ -3428,7 +3426,7 @@ static int set_internal_buffers(struct msm_vidc_inst *inst, return 0; return allocate_and_set_internal_bufs(inst, internal_buf, - buf_list, true); + buf_list); } int msm_comm_try_state(struct msm_vidc_inst *inst, int state) @@ -3589,6 +3587,39 @@ int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd) "Failed to flush buffers: %d\n", rc); } break; + case V4L2_DEC_QCOM_CMD_RECONFIG_HINT: + { + u32 *ptr = NULL; + struct hal_buffer_requirements *output_buf; + + rc = msm_comm_try_get_bufreqs(inst); + if (rc) { + dprintk(VIDC_ERR, + "Getting buffer requirements failed: %d\n", + rc); + break; + } + + output_buf = get_buff_req_buffer(inst, + msm_comm_get_hal_output_buffer(inst)); + if (output_buf) { + if (dec) { + ptr = (u32 *)dec->raw.data; + ptr[0] = output_buf->buffer_size; + ptr[1] = output_buf->buffer_count_actual; + dprintk(VIDC_DBG, + "Reconfig hint, size is %u, count is %u\n", + ptr[0], ptr[1]); + } else { + dprintk(VIDC_ERR, "Null decoder\n"); + } + } else { + dprintk(VIDC_DBG, + "This output buffer not required, buffer_type: %x\n", + HAL_BUFFER_OUTPUT); + } + break; + } default: dprintk(VIDC_ERR, "Unknown Command %d\n", which_cmd); rc = -ENOTSUPP; @@ -4422,15 +4453,15 @@ error: return rc; } -int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst, - bool max_int_buffer) { +int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst) +{ int rc = 0; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); return -EINVAL; } - if (!max_int_buffer && msm_comm_release_scratch_buffers(inst, true)) + if (msm_comm_release_scratch_buffers(inst, true)) dprintk(VIDC_WARN, "Failed to release scratch buffers\n"); rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index 5658df95db26c78a118448f24dcc6a668c401539..7d28859c040c32c6a7286fc91ec5d924cc9da966 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -41,13 +41,9 @@ int msm_comm_try_set_prop(struct msm_vidc_inst *inst, enum hal_property ptype, void *pdata); int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, union hal_get_property *hprop); -int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst, - bool max_int_buffer); +int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst); int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst); int msm_comm_set_output_buffers(struct msm_vidc_inst *inst); -int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, - struct hal_buffer_requirements *internal_bufreq, - struct msm_vidc_list *buf_list, bool set_on_fw); int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst); int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb); void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index 2be52b10c84bff5237cf90f72952b286e2212c18..5c13b6fef3ec0c015e40edd8e640c297e12ef320 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -445,7 +445,7 @@ struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "Invalid params, inst: %pK\n", inst); goto exit; } - snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%pK", inst); + snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst); idata = kzalloc(sizeof(struct core_inst_pair), GFP_KERNEL); if (!idata) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index a1b4ad48b054e493cbeab61ae6902a1437f0522d..3a329d98991858e1841ba2acdf28cf4ec9011915 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -106,7 +106,6 @@ struct clock_info { u32 count; bool has_scaling; bool has_mem_retention; - unsigned long rate_on_enable; }; struct clock_set { diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 20f02ce46029fb2f0ada3af7c9114dff87e2a63e..72b0a6368f143055d4aa3ac8118e106303e7fb68 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -1574,7 +1579,6 @@ static int __scale_clocks(struct venus_hfi_device *device, return rc; } - static int venus_hfi_scale_clocks(void *dev, int load, struct vidc_clk_scale_data *data, unsigned long instant_bitrate) @@ -1601,41 +1605,6 @@ exit: return rc; } -static void __save_clock_rate(struct venus_hfi_device *device, bool reset) -{ - struct clock_info *cl; - - venus_hfi_for_each_clock(device, cl) { - if (cl->has_scaling) { - cl->rate_on_enable = - reset ? 0 : clk_get_rate(cl->clk); - dprintk(VIDC_PROF, "Saved clock %s rate %lu\n", - cl->name, cl->rate_on_enable); - } - } -} - -static void __restore_clock_rate(struct venus_hfi_device *device) -{ - struct clock_info *cl; - - venus_hfi_for_each_clock(device, cl) { - if (cl->has_scaling && cl->rate_on_enable) { - int rc; - - rc = __set_clk_rate(device, cl, cl->rate_on_enable); - if (rc) - dprintk(VIDC_ERR, - "Failed to restore clock %s rate %lu\n", - cl->name, cl->rate_on_enable); - else - dprintk(VIDC_DBG, - "Restored clock %s rate %lu\n", - cl->name, cl->rate_on_enable); - } - } -} - /* Writes into cmdq without raising an interrupt */ static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device, void *pkt, bool *requires_interrupt) @@ -3283,6 +3252,8 @@ static void venus_hfi_pm_handler(struct work_struct *work) const int max_tries = 5; struct venus_hfi_device *device = list_first_entry( &hal_ctxt.dev_head, struct venus_hfi_device, list); + char msg[SUBSYS_CRASH_REASON_LEN]; + if (!device) { dprintk(VIDC_ERR, "%s: NULL device\n", __func__); return; @@ -3296,6 +3267,9 @@ static void venus_hfi_pm_handler(struct work_struct *work) dprintk(VIDC_WARN, "Failed to PC for %d times\n", device->skip_pc_count); device->skip_pc_count = 0; + snprintf(msg, sizeof(msg), + "Failed to prepare for PC, rc : %d\n", rc); + subsystem_crash_reason("venus", msg); __process_fatal_error(device); return; } @@ -3374,6 +3348,15 @@ exit: return; } +static void venus_hfi_crash_reason(struct hfi_sfr_struct *vsfr) +{ + char msg[SUBSYS_CRASH_REASON_LEN]; + + snprintf(msg, sizeof(msg), "SFR Message from FW : %s", + vsfr->rg_data); + subsystem_crash_reason("venus", msg); +} + static void __process_sys_error(struct venus_hfi_device *device) { struct hfi_sfr_struct *vsfr = NULL; @@ -3398,6 +3381,7 @@ static void __process_sys_error(struct venus_hfi_device *device) dprintk(VIDC_ERR, "SFR Message from FW: %s\n", vsfr->rg_data); + venus_hfi_crash_reason(vsfr); } } @@ -3495,9 +3479,11 @@ static int __response_handler(struct venus_hfi_device *device) } }; - if (vsfr) + if (vsfr) { dprintk(VIDC_ERR, "SFR Message from FW: %s\n", vsfr->rg_data); + venus_hfi_crash_reason(vsfr); + } dprintk(VIDC_ERR, "Received watchdog timeout\n"); packets[packet_count++] = info; @@ -4352,7 +4338,6 @@ static inline int __suspend(struct venus_hfi_device *device) goto err_tzbsp_suspend; } - __save_clock_rate(device, false); __venus_power_off(device, true); dprintk(VIDC_PROF, "Venus power collapsed\n"); return rc; @@ -4382,7 +4367,6 @@ static inline int __resume(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Failed to power on venus\n"); goto err_venus_power_on; } - __restore_clock_rate(device); /* Reboot the firmware */ rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME); @@ -4420,7 +4404,6 @@ exit: err_reset_core: __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND); err_set_video_state: - __save_clock_rate(device, true); __venus_power_off(device, true); err_venus_power_on: dprintk(VIDC_ERR, "Failed to resume from power collapse\n"); @@ -4479,7 +4462,6 @@ fail_protect_mem: subsystem_put(device->resources.fw.cookie); device->resources.fw.cookie = NULL; fail_load_fw: - __save_clock_rate(device, true); __venus_power_off(device, true); fail_venus_power_on: fail_init_pkt: @@ -4501,7 +4483,6 @@ static void __unload_fw(struct venus_hfi_device *device) __vote_buses(device, NULL, 0); subsystem_put(device->resources.fw.cookie); __interface_queues_release(device); - __save_clock_rate(device, true); __venus_power_off(device, false); device->resources.fw.cookie = NULL; __deinit_resources(device); diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index 1b7ec0870c2a8e0a8e772bcf93f15d701fa1a1e0..07763d4fc292009f6d6da7cb8af9602cd5fd9cb1 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c index 268fcd89ebedd1ec087c36a8208a708c959a2e4e..27249eeec013822497e2ebd2d8cb74caea7158d0 100644 --- a/drivers/mfd/wcd934x-regmap.c +++ b/drivers/mfd/wcd934x-regmap.c @@ -1932,10 +1932,12 @@ static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg) case WCD934X_ANA_BIAS: case WCD934X_ANA_BUCK_CTL: case WCD934X_ANA_RCO: + case WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL: case WCD934X_CODEC_RPM_CLK_GATE: case WCD934X_BIAS_VBG_FINE_ADJ: case WCD934X_CODEC_CPR_SVS_CX_VDD: case WCD934X_CODEC_CPR_SVS2_CX_VDD: + case WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL: return true; } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d86795bf9453a02e7b481e52d3800dd63e67e32f..98af91da8c583bd3514523a1c67e0101fec931dd 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -412,6 +412,10 @@ config TI_DAC7512 This driver can also be built as a module. If so, the module will be called ti_dac7512. +config UID_STAT + bool "UID based statistics tracking exported to /proc/uid_stat" + default n + config VMWARE_BALLOON tristate "VMware Balloon Driver" depends on VMWARE_VMCI && X86 && HYPERVISOR_GUEST @@ -571,6 +575,108 @@ config MEMORY_STATE_TIME help Memory time statistics exported to /sys/kernel/memory_state_time +config NFC_PN547 + tristate "NFC driver for PN547" + depends on I2C + default n + help + his option enables device driver for PN547. + GPIO, and PMIC GPIO configurations are controlled. + The sysfs files provides the interface to send and receive + the data, response and notification. + +config LDO_VIBRATOR + tristate "LDO Vibrator" + default n + help + This option enables device driver support for the vibrator + on the LDO line. The vibrator is controlled using the + timed output class. + +config TOF_SENSOR + tristate "ToF Sensor" + depends on I2C + ---help--- + Say Y here if you want to use ToF sensor. + + To compile this driver as a module, choose M here: the + module will be called tof_sensor. + +config SENSORS_TCS3490 + tristate "AMS TCS3490 Sensor Driver" + depends on I2C + default n + help + If you say yes here you get support for the AMS tcs3490, + ALS and color light sensors. + This driver can also be build as module. + +config SIM_DETECT + tristate "SIM_DETECT driver support" + default n + help + Say Y here + if you want to support SIM_DETECT as detection device. + This driver can be used for sending notifications via + switch_class when sim card is inserted or removed. + +config RAMDUMP_TAGS + bool "Ramdump tags to communicate between kernel and ramdump" + default n + depends on !RAMDUMP_CRASH_LOGS + help + This option enables a driver which can be interacted with to + supply the ramdumper with more information about the current + state of the crashing kernel such as build info, HWWD registers, + additional CPU registers not stored in crash_notes, crashing + application info etc. A small amount of memory will be set + aside to hold the information which will later be used by + the ramdump application. + +config RAMDUMP_MEMDESC + bool "Ramdump memory descriptors" + default n + help + This is a ramdump_mem_desc driver which adds the + memory descriptors in Normal mode into a piece of debug memory + and split the contents and exports it as /proc/mem_desc + in Ramdump mode to support ramdump functionality + +config POWERKEY_FORCECRASH + tristate "Force a crash on powerkey long press" + default n + help + Say Y here if you want force crash functionality through power + key. Triggers panic if power key is hold for more than 10secs. + +config CXD224X_NFC + bool "CXD224X driver for FeliCa and NFC" + depends on I2C + default n + help + This option enables device driver support for Sony CXD224X + series. This driver enables the control of CXD224X series + device by using I2C. Furthermore, this driver enables the + control of PON using device file. + +config BD7602_POWER_IC + bool "BD7602 Power IC control" + depends on I2C + default n + help + This option enables device driver support for BD7602 Power IC + control device. + +config ONESEG_TUNER_SMTVJ19X + tristate "ONESEG tuner driver for SMT-VJ19x" + default n + depends on SPI + help + Select this module to enable 1seg Tuner Driver which supports + 1seg contents viewing. + This module controls power switching and reset switching of + SMT-VJ19x. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" @@ -584,4 +690,5 @@ source "drivers/misc/mic/Kconfig" source "drivers/misc/genwqe/Kconfig" source "drivers/misc/echo/Kconfig" source "drivers/misc/cxl/Kconfig" +source "drivers/misc/mm_tuner/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b0718228d2d933ca796487915aa0b427c4c8406b..7c04796211875b555b3d1a023315af7c43e9933d 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -18,10 +18,12 @@ obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o +obj-$(CONFIG_NFC_PN547) += pn547.o obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o +obj-$(CONFIG_SIM_DETECT) += sim_detect.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o @@ -35,6 +37,7 @@ obj-$(CONFIG_ISL29020) += isl29020.o obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o obj-$(CONFIG_DS1682) += ds1682.o obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o +obj-$(CONFIG_UID_STAT) += uid_stat.o obj-$(CONFIG_C2PORT) += c2port/ obj-$(CONFIG_HMC6352) += hmc6352.o obj-y += eeprom/ @@ -63,6 +66,16 @@ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_UID_SYS_STATS) += uid_sys_stats.o +obj-$(CONFIG_BD7602_POWER_IC) += bd7602.o +obj-$(CONFIG_CXD224X_NFC) += cxd224x-i2c.o obj-y += qcom/ obj-$(CONFIG_QPNP_MISC) += qpnp-misc.o obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o +obj-$(CONFIG_LDO_VIBRATOR) += ldo_vibrator.o +obj-$(CONFIG_TOF_SENSOR) += tof_sensor.o +obj-$(CONFIG_SENSORS_TCS3490) += tcs3490.o +obj-$(CONFIG_RAMDUMP_TAGS) += rdtags.o +obj-$(CONFIG_RAMDUMP_MEMDESC) += ramdump_mem_desc.o +obj-$(CONFIG_POWERKEY_FORCECRASH) += powerkey_forcecrash.o +obj-$(CONFIG_MMTUNER_MN8855x) += mm_tuner/ +obj-$(CONFIG_ONESEG_TUNER_SMTVJ19X) += oneseg_tuner_drv.o \ No newline at end of file diff --git a/drivers/misc/bd7602.c b/drivers/misc/bd7602.c new file mode 100644 index 0000000000000000000000000000000000000000..3fbd6a101af58b0051988aa8d81a4e252d3be5ad --- /dev/null +++ b/drivers/misc/bd7602.c @@ -0,0 +1,302 @@ +/* drivers/misc/bd7602.c + * + * Author: Manabu Yoshida + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#define BD7602_DEVICE_NAME "bd7602" +#define BD7602_MODE_MAX 0x04 + +struct bd7602_dev { + struct mutex mutex; + struct i2c_client *client; + u8 mode; +}; + +static ssize_t bd7602_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret; + u8 mode; + struct bd7602_dev *bd7602_dev = dev_get_drvdata(dev); + + if (!bd7602_dev) { + ret = -ENODEV; + goto err; + } + + if (sizeof(mode) != size) { + dev_err(dev, "%s: Invalid size %ld\n", __func__, size); + ret = -EINVAL; + goto err; + } + + memcpy(&mode, buf, size); + if (BD7602_MODE_MAX < mode) { + dev_err(dev, "%s: Invalid mode 0x%02x\n", __func__, mode); + ret = -EINVAL; + goto err; + } + + mutex_lock(&bd7602_dev->mutex); + bd7602_dev->mode = mode; + mutex_unlock(&bd7602_dev->mutex); + dev_info(dev, "%s: mode: 0x%02x\n", __func__, bd7602_dev->mode); + + return size; + +err: + return ret; +} + +static ssize_t bd7602_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct bd7602_dev *bd7602_dev = dev_get_drvdata(dev); + + if (!bd7602_dev) { + ret = -ENODEV; + goto err; + } + + mutex_lock(&bd7602_dev->mutex); + memcpy(buf, &bd7602_dev->mode, sizeof(bd7602_dev->mode)); + mutex_unlock(&bd7602_dev->mutex); + dev_info(dev, "%s: mode: 0x%02x\n", __func__, bd7602_dev->mode); + + return sizeof(bd7602_dev->mode); + +err: + return ret; +} + +static ssize_t bd7602_value_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + u8 data[2]; + int ret; + int len = 2; + struct bd7602_dev *bd7602_dev = dev_get_drvdata(dev); + + if (!bd7602_dev) { + ret = -ENODEV; + goto err; + } + + if (sizeof(u8) != size) { + dev_err(dev, "%s: Invalid size %ld\n", __func__, size); + ret = -EINVAL; + goto err; + } + + mutex_lock(&bd7602_dev->mutex); + data[0] = bd7602_dev->mode; + memcpy(&data[1], buf, size); + ret = i2c_master_send(bd7602_dev->client, data, len); + if (ret != len) { + mutex_unlock(&bd7602_dev->mutex); + dev_err(dev, "%s: Failed to write %d\n", __func__, ret); + ret = -EIO; + goto err; + } + mutex_unlock(&bd7602_dev->mutex); + + dev_info(dev, "%s: mode:0x%02x value:0x%02x\n", + __func__, data[0], data[1]); + + return size; + +err: + return ret; +} + +static ssize_t bd7602_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + int ret; + struct bd7602_dev *bd7602_dev = dev_get_drvdata(dev); + + if (!bd7602_dev) { + ret = -ENODEV; + goto err; + } + + mutex_lock(&bd7602_dev->mutex); + ret = i2c_master_send(bd7602_dev->client, &bd7602_dev->mode, + sizeof(bd7602_dev->mode)); + if (sizeof(bd7602_dev->mode) != ret) { + mutex_unlock(&bd7602_dev->mutex); + dev_err(dev, "%s: Failed to write %d\n", __func__, ret); + ret = -EIO; + goto err; + } + + ret = i2c_master_recv(bd7602_dev->client, &data, sizeof(data)); + if (sizeof(data) != ret) { + mutex_unlock(&bd7602_dev->mutex); + dev_err(dev, "%s: Failed to read %d\n", __func__, ret); + ret = -EIO; + goto err; + } + + memcpy(buf, &data, sizeof(data)); + mutex_unlock(&bd7602_dev->mutex); + + dev_info(dev, "%s: mode:0x%02x value:0x%02x\n", + __func__, bd7602_dev->mode, data); + + return sizeof(data); + +err: + return ret; +} + +static struct device_attribute bd7602_sysfs_attrs[] = { + __ATTR(mode, S_IRUSR | S_IWUSR, bd7602_mode_show, bd7602_mode_store), + __ATTR(value, S_IRUSR | S_IWUSR, bd7602_value_show, bd7602_value_store), +}; + +static int bd7602_create_sysfs_entries(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bd7602_sysfs_attrs); i++) + if (device_create_file(dev, bd7602_sysfs_attrs + i)) + goto err_create_file; + return 0; + +err_create_file: + for (i = i - 1; i >= 0; i--) + device_remove_file(dev, bd7602_sysfs_attrs + i); + + dev_err(dev, "Unable to create sysfs interfaces\n"); + + return -EIO; +} + +static void bd7602_remove_sysfs_entries(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bd7602_sysfs_attrs); i++) + device_remove_file(dev, bd7602_sysfs_attrs + i); +} + +static int bd7602_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct bd7602_dev *bd7602_dev; + + dev_info(&client->dev, "%s, probing bd7602 driver flags = %x\n", + __func__, client->flags); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "need I2C_FUNC_I2C\n"); + ret = -ENODEV; + goto err_exit; + } + + bd7602_dev = kzalloc(sizeof(*bd7602_dev), GFP_KERNEL); + if (bd7602_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_kzalloc; + } + + bd7602_dev->client = client; + i2c_set_clientdata(client, bd7602_dev); + + mutex_init(&bd7602_dev->mutex); + + ret = bd7602_create_sysfs_entries(&client->dev); + if (ret) { + dev_err(&client->dev, "bd7602_create_sysfs_entries failed\n"); + goto err_create_sysfs_entries; + } + + dev_info(&client->dev, + "%s, probing bd7602 driver exited successfully\n", + __func__); + return 0; + +err_create_sysfs_entries: + mutex_destroy(&bd7602_dev->mutex); + i2c_set_clientdata(client, NULL); + kzfree(bd7602_dev); +err_kzalloc: +err_exit: + return ret; +} + +static int bd7602_remove(struct i2c_client *client) +{ + struct bd7602_dev *bd7602_dev = i2c_get_clientdata(client); + + bd7602_remove_sysfs_entries(&client->dev); + mutex_destroy(&bd7602_dev->mutex); + i2c_set_clientdata(client, NULL); + kzfree(bd7602_dev); + + return 0; +} + +static const struct i2c_device_id bd7602_id[] = { + { BD7602_DEVICE_NAME, 0 }, + { } +}; + +static struct of_device_id bd7602_match_table[] = { + { .compatible = "rohm,bd7602", }, + { }, +}; + +static struct i2c_driver bd7602_driver = { + .id_table = bd7602_id, + .probe = bd7602_probe, + .remove = bd7602_remove, + .driver = { + .owner = THIS_MODULE, + .name = BD7602_DEVICE_NAME, + .of_match_table = bd7602_match_table, + }, +}; + +static int __init bd7602_dev_init(void) +{ + return i2c_add_driver(&bd7602_driver); +} +module_init(bd7602_dev_init); + +static void __exit bd7602_dev_exit(void) +{ + i2c_del_driver(&bd7602_driver); +} +module_exit(bd7602_dev_exit); + +MODULE_AUTHOR("Manabu Yoshida "); +MODULE_DESCRIPTION("ROHM BD7602 Power IC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/cxd224x-i2c.c b/drivers/misc/cxd224x-i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..c33662c95d4846287f50c92d8a457affb83535ba --- /dev/null +++ b/drivers/misc/cxd224x-i2c.c @@ -0,0 +1,671 @@ +/* drivers/misc/cxd224x-i2c.c + * + * Copyright (C) 2013 Sony Corporation. + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* do not change below */ +#define MAX_BUFFER_SIZE 780 + +/* Read data */ +#define PACKET_HEADER_SIZE_NCI (3) +#define PACKET_HEADER_SIZE_HCI (3) +#define PACKET_TYPE_NCI (16) +#define PACKET_TYPE_HCIEV (4) +#define MAX_PACKET_SIZE (PACKET_HEADER_SIZE_NCI + 255) + +#define CXD224X_WAKE_LOCK_TIMEOUT 3 +#define CXD224X_WAKE_LOCK_NAME CXD224X_DEVICE_NAME +#define CXD224X_WAKE_LOCK_TIMEOUT_LP 3 +#define CXD224X_WAKE_LOCK_NAME_LP "cxd224x-i2c-lp" + +#define CXD224X_PINCTRL_ACTIVE "felica_active" +#define CXD224X_PINCTRL_SUSPEND "felica_suspend" + +struct cxd224x_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice cxd224x_device; + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + unsigned int irq_gpio; + unsigned int wake_gpio; + bool irq_enabled; + spinlock_t irq_enabled_lock; + unsigned int count_irq; + struct wake_lock wakelock; + struct wake_lock wakelock_lp; +}; + +static void cxd224x_init_stat(struct cxd224x_dev *cxd224x_dev) +{ + cxd224x_dev->count_irq = 0; +} + +static void cxd224x_disable_irq(struct cxd224x_dev *cxd224x_dev) +{ + unsigned long flags; + spin_lock_irqsave(&cxd224x_dev->irq_enabled_lock, flags); + if (cxd224x_dev->irq_enabled) { + disable_irq_nosync(cxd224x_dev->client->irq); + cxd224x_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&cxd224x_dev->irq_enabled_lock, flags); +} + +static void cxd224x_enable_irq(struct cxd224x_dev *cxd224x_dev) +{ + unsigned long flags; + spin_lock_irqsave(&cxd224x_dev->irq_enabled_lock, flags); + if (!cxd224x_dev->irq_enabled) { + cxd224x_dev->irq_enabled = true; + enable_irq(cxd224x_dev->client->irq); + } + spin_unlock_irqrestore(&cxd224x_dev->irq_enabled_lock, flags); +} + +static irqreturn_t cxd224x_dev_irq_handler(int irq, void *dev_id) +{ + struct cxd224x_dev *cxd224x_dev = dev_id; + unsigned long flags; + + spin_lock_irqsave(&cxd224x_dev->irq_enabled_lock, flags); + cxd224x_dev->count_irq++; + spin_unlock_irqrestore(&cxd224x_dev->irq_enabled_lock, flags); + wake_up(&cxd224x_dev->read_wq); + + dev_info(&cxd224x_dev->client->dev, "%s\n", __func__); + + return IRQ_HANDLED; +} + +static unsigned int cxd224x_dev_poll(struct file *filp, poll_table *wait) +{ + struct cxd224x_dev *cxd224x_dev = filp->private_data; + unsigned int mask = 0; + unsigned long flags; + + poll_wait(filp, &cxd224x_dev->read_wq, wait); + + spin_lock_irqsave(&cxd224x_dev->irq_enabled_lock, flags); + if (cxd224x_dev->count_irq > 0) { + cxd224x_dev->count_irq--; + mask |= POLLIN | POLLRDNORM; + } + spin_unlock_irqrestore(&cxd224x_dev->irq_enabled_lock, flags); + + if (mask) + wake_lock_timeout(&cxd224x_dev->wakelock, + CXD224X_WAKE_LOCK_TIMEOUT * HZ); + return mask; +} + +static ssize_t cxd224x_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct cxd224x_dev *cxd224x_dev = filp->private_data; + unsigned char tmp[MAX_BUFFER_SIZE]; + int total, len, ret; + + total = 0; + len = 0; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + mutex_lock(&cxd224x_dev->read_mutex); + + ret = i2c_master_recv(cxd224x_dev->client, tmp, 3); + if (ret == 3 && (tmp[0] != 0xff)) { + total = ret; + + len = tmp[PACKET_HEADER_SIZE_NCI-1]; + + /* make sure full packet fits in the buffer */ + if (len > 0 && (len + total) <= count) { + /* read the remainder of the packet */ + ret = i2c_master_recv(cxd224x_dev->client, tmp+total, + len); + if (ret == len) + total += len; + } + } + + mutex_unlock(&cxd224x_dev->read_mutex); + + if (total > count || copy_to_user(buf, tmp, total)) { + dev_err(&cxd224x_dev->client->dev, + "failed to copy to user space, total = %d\n", total); + total = -EFAULT; + } + + return total; +} + +static ssize_t cxd224x_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct cxd224x_dev *cxd224x_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) { + dev_err(&cxd224x_dev->client->dev, "out of memory\n"); + return -ENOMEM; + } + + if (copy_from_user(tmp, buf, count)) { + dev_err(&cxd224x_dev->client->dev, + "failed to copy from user space\n"); + return -EFAULT; + } + + mutex_lock(&cxd224x_dev->read_mutex); + /* Write data */ + + ret = i2c_master_send(cxd224x_dev->client, tmp, count); + if (ret != count) { + dev_err(&cxd224x_dev->client->dev, + "failed to write %d\n", ret); + ret = -EIO; + } + mutex_unlock(&cxd224x_dev->read_mutex); + + return ret; +} + +static int cxd224x_dev_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + struct cxd224x_dev *cxd224x_dev = container_of(filp->private_data, + struct cxd224x_dev, + cxd224x_device); + filp->private_data = cxd224x_dev; + cxd224x_init_stat(cxd224x_dev); + cxd224x_enable_irq(cxd224x_dev); + dev_info(&cxd224x_dev->client->dev, + "%d,%d\n", imajor(inode), iminor(inode)); + + return ret; +} + +static const struct file_operations cxd224x_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .poll = cxd224x_dev_poll, + .read = cxd224x_dev_read, + .write = cxd224x_dev_write, + .open = cxd224x_dev_open, +}; + +static ssize_t cxd224x_dev_wake_ctl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u8 mode; + int ret, size; + struct cxd224x_dev *cxd224x_dev = dev_get_drvdata(dev); + + + if (!cxd224x_dev) { + ret = -ENODEV; + goto err; + } + ret = gpio_get_value_cansleep(cxd224x_dev->wake_gpio); + if (ret < 0) { + dev_err(dev, "%s: Unable to read WAKE GPIO\n", __func__); + goto err; + } + mode = !ret; + size = sizeof(mode); + memcpy(buf, &mode, size); + + return size; + +err: + return ret; +} + +static ssize_t cxd224x_dev_wake_ctl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + u8 mode; + int ret, value; + struct cxd224x_dev *cxd224x_dev = dev_get_drvdata(dev); + + if (!cxd224x_dev) { + ret = -ENODEV; + goto err; + } + + if (sizeof(mode) != size) { + dev_err(dev, "%s: Invalid size %ld\n", __func__, size); + ret = -EINVAL; + goto err; + } + + memcpy(&mode, buf, size); + value = mode ? 0 : 1; + if (1 == value) { + wake_lock_timeout(&cxd224x_dev->wakelock_lp, CXD224X_WAKE_LOCK_TIMEOUT_LP*HZ); + gpio_set_value_cansleep(cxd224x_dev->wake_gpio, 1); + } else if (0 == value) { + gpio_set_value_cansleep(cxd224x_dev->wake_gpio, 0); + wake_unlock(&cxd224x_dev->wakelock_lp); + } else { + /* do nothing */ + } + return size; + +err: + return ret; +} + +static struct device_attribute cxd224x_sysfs_attrs[] = { + __ATTR(wake_ctl, S_IRUSR | S_IWUSR, cxd224x_dev_wake_ctl_show, + cxd224x_dev_wake_ctl_store), +}; + +static int cxd224x_pinctrl_init(struct device *dev, struct cxd224x_dev *cxd224x_dev) +{ + int ret = 0; + + cxd224x_dev->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(cxd224x_dev->pinctrl)) { + dev_err(dev, "error devm_pinctrl_get() failed err:%ld\n", + PTR_ERR(cxd224x_dev->pinctrl)); + ret = PTR_ERR(cxd224x_dev->pinctrl); + goto out; + } + + cxd224x_dev->gpio_state_active = pinctrl_lookup_state( + cxd224x_dev->pinctrl, CXD224X_PINCTRL_ACTIVE); + + if (IS_ERR_OR_NULL(cxd224x_dev->gpio_state_active)) { + ret = PTR_ERR(cxd224x_dev->gpio_state_active); + dev_info(dev, "note pinctrl_lookup_state(%s) err:%d\n", + CXD224X_PINCTRL_ACTIVE, ret); + goto out; + } + + cxd224x_dev->gpio_state_suspend = pinctrl_lookup_state( + cxd224x_dev->pinctrl, CXD224X_PINCTRL_SUSPEND); + + if (IS_ERR_OR_NULL(cxd224x_dev->gpio_state_suspend)) { + ret = PTR_ERR(cxd224x_dev->gpio_state_suspend); + dev_info(dev, "note pinctrl_lookup_state(%s) err:%d\n", + CXD224X_PINCTRL_ACTIVE, ret); + goto out; + } + +out: + return ret; +} + +static void cxd224x_pinctrl_select_state(struct device *dev, bool active) +{ + struct cxd224x_dev *cxd224x_dev = dev_get_drvdata(dev); + struct pinctrl_state *pins_state; + const char *pins_state_name; + + if (active) { + pins_state = cxd224x_dev->gpio_state_active; + pins_state_name = CXD224X_PINCTRL_ACTIVE; + } else { + pins_state = cxd224x_dev->gpio_state_suspend; + pins_state_name = CXD224X_PINCTRL_SUSPEND; + } + + if (!IS_ERR_OR_NULL(pins_state)) { + int ret = pinctrl_select_state(cxd224x_dev->pinctrl, + pins_state); + if (ret) + dev_err(dev, "error pinctrl_select_state(%s) err:%d\n", + pins_state_name, ret); + } else { + dev_err(dev, + "error pinctrl state-name:'%s' is not configured\n", + pins_state_name); + } +} + +static int cxd224x_create_sysfs_entries(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cxd224x_sysfs_attrs); i++) + if (device_create_file(dev, cxd224x_sysfs_attrs + i)) + goto err_create_file; + return 0; + +err_create_file: + for (i = i - 1; i >= 0; i--) + device_remove_file(dev, cxd224x_sysfs_attrs + i); + + dev_err(dev, "Unable to create sysfs interfaces\n"); + + return -EIO; +} + +static void cxd224x_remove_sysfs_entries(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cxd224x_sysfs_attrs); i++) + device_remove_file(dev, cxd224x_sysfs_attrs + i); +} + +static struct cxd224x_platform_data *cxd224x_dt_to_pdata(struct device *dev) +{ + int ret; + struct device_node *node = dev->of_node; + struct cxd224x_platform_data *pdata; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "unable to allocate memory for platform data\n"); + ret = -ENOMEM; + goto err; + } + pdata->irq_gpio = of_get_named_gpio(node, "cxd224x,irq_gpio", 0); + if (!gpio_is_valid(pdata->irq_gpio)) { + ret = -EINVAL; + dev_err(dev, + "failed to of_get_named_gpio(cxd224x,irq_gpio)\n"); + goto err; + } + pdata->wake_gpio = of_get_named_gpio(node, "cxd224x,wake_gpio", 0); + if (!gpio_is_valid(pdata->wake_gpio)) { + ret = -EINVAL; + dev_err(dev, + "failed to of_get_named_gpio(cxd224x,wake_gpio)\n"); + goto err; + } + + return pdata; +err: + if (pdata) + devm_kfree(dev, pdata); + + return ERR_PTR(ret); +} + +static int cxd224x_gpio_request(struct device *dev, + struct cxd224x_platform_data *pdata) +{ + int ret; + + ret = gpio_request(pdata->irq_gpio, "cxd224x_irq"); + if (ret) + goto err_irq; + ret = gpio_request(pdata->wake_gpio, "cxd224x_wake"); + if (ret) + goto err_wake; + + return 0; + +err_wake: + gpio_free(pdata->wake_gpio); +err_irq: + gpio_free(pdata->irq_gpio); + + dev_err(dev, "%s: failed to gpio request %d\n", __func__, ret); + return ret; +} + +static void cxd224x_gpio_free(struct device *dev, + struct cxd224x_platform_data *pdata) +{ + gpio_free(pdata->wake_gpio); + gpio_free(pdata->irq_gpio); +} + +static int cxd224x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct cxd224x_platform_data *platform_data; + struct cxd224x_dev *cxd224x_dev; + struct clk *felica_clk = NULL; + + platform_data = client->dev.platform_data; + + dev_info(&client->dev, "%s, probing cxd224x driver flags = %x\n", + __func__, client->flags); + + if (client->dev.of_node) { + platform_data = cxd224x_dt_to_pdata(&client->dev); + if (IS_ERR(platform_data)) { + ret = PTR_ERR(platform_data); + dev_err(&client->dev, "failed to dt_to_pdata\n"); + goto err_exit; + } + client->dev.platform_data = platform_data; + } + + if (platform_data == NULL) { + dev_err(&client->dev, "nfc probe fail\n"); + ret = -ENODEV; + goto err_exit; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "need I2C_FUNC_I2C\n"); + ret = -ENODEV; + goto err_exit; + } + + ret = cxd224x_gpio_request(&client->dev, platform_data); + if (ret) { + dev_err(&client->dev, "failed to gpio_request\n"); + goto err_exit; + } + + cxd224x_dev = kzalloc(sizeof(*cxd224x_dev), GFP_KERNEL); + if (cxd224x_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_kzalloc; + } + + cxd224x_dev->irq_gpio = platform_data->irq_gpio; + cxd224x_dev->wake_gpio = platform_data->wake_gpio; + cxd224x_dev->client = client; + wake_lock_init(&cxd224x_dev->wakelock, WAKE_LOCK_SUSPEND, + CXD224X_WAKE_LOCK_NAME); + wake_lock_init(&cxd224x_dev->wakelock_lp, WAKE_LOCK_SUSPEND, CXD224X_WAKE_LOCK_NAME_LP); + + /* init mutex and queues */ + init_waitqueue_head(&cxd224x_dev->read_wq); + mutex_init(&cxd224x_dev->read_mutex); + spin_lock_init(&cxd224x_dev->irq_enabled_lock); + + ret = cxd224x_pinctrl_init(&client->dev, cxd224x_dev); + if (ret) { + dev_err(&client->dev, "pinctrl_init failed\n"); + goto err_pinctrl_init; + } + + cxd224x_dev->cxd224x_device.minor = MISC_DYNAMIC_MINOR; + cxd224x_dev->cxd224x_device.name = CXD224X_DEVICE_NAME; + cxd224x_dev->cxd224x_device.fops = &cxd224x_dev_fops; + + ret = misc_register(&cxd224x_dev->cxd224x_device); + if (ret) { + dev_err(&client->dev, "misc_register failed\n"); + goto err_misc_register; + } + + felica_clk = clk_get(&client->dev, "felica_clk"); + if (IS_ERR(felica_clk)) { + dev_err(&client->dev, "Couldn't get felica_clk\n"); + goto err_clk; + } + ret = clk_prepare_enable(felica_clk); + if (ret) { + dev_err(&client->dev, "failed to enable felica_clk\n"); + goto err_clk_enable; + } + + ret = cxd224x_create_sysfs_entries(&client->dev); + if (ret) { + dev_err(&client->dev, "create_sysfs_entries failed\n"); + goto err_create_sysfs_entries; + } + + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + dev_info(&client->dev, "requesting IRQ %d\n", client->irq); + cxd224x_dev->irq_enabled = true; + ret = request_threaded_irq(client->irq, NULL, cxd224x_dev_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + client->name, cxd224x_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + + cxd224x_disable_irq(cxd224x_dev); + i2c_set_clientdata(client, cxd224x_dev); + cxd224x_pinctrl_select_state(&client->dev, true); + device_init_wakeup(&client->dev, 1); + + dev_info(&client->dev, + "%s, probing cxd224x driver exited successfully\n", + __func__); + + return 0; + +err_request_irq_failed: + cxd224x_remove_sysfs_entries(&client->dev); +err_create_sysfs_entries: + misc_deregister(&cxd224x_dev->cxd224x_device); +err_clk_enable: + clk_put(felica_clk); +err_clk: +err_misc_register: +err_pinctrl_init: + mutex_destroy(&cxd224x_dev->read_mutex); + wake_lock_destroy(&cxd224x_dev->wakelock); + kzfree(cxd224x_dev); +err_kzalloc: + cxd224x_gpio_free(&client->dev, platform_data); +err_exit: + return ret; +} + +static int cxd224x_remove(struct i2c_client *client) +{ + struct cxd224x_dev *cxd224x_dev = i2c_get_clientdata(client); + + free_irq(client->irq, cxd224x_dev); + cxd224x_remove_sysfs_entries(&client->dev); + misc_deregister(&cxd224x_dev->cxd224x_device); + mutex_destroy(&cxd224x_dev->read_mutex); + wake_lock_destroy(&cxd224x_dev->wakelock); + wake_lock_destroy(&cxd224x_dev->wakelock_lp); + i2c_set_clientdata(client, NULL); + kzfree(cxd224x_dev); + cxd224x_gpio_free(&client->dev, client->dev.platform_data); + + return 0; +} + +#ifdef CONFIG_PM +static int cxd224x_suspend(struct device *dev) +{ + struct cxd224x_dev *cxd224x_dev = dev_get_drvdata(dev); + + if (device_may_wakeup(&cxd224x_dev->client->dev)) + enable_irq_wake(cxd224x_dev->client->irq); + + cxd224x_pinctrl_select_state(dev, false); + + return 0; +} + +static int cxd224x_resume(struct device *dev) +{ + struct cxd224x_dev *cxd224x_dev = dev_get_drvdata(dev); + + if (device_may_wakeup(&cxd224x_dev->client->dev)) + disable_irq_wake(cxd224x_dev->client->irq); + + cxd224x_pinctrl_select_state(dev, true); + + return 0; +} + +static const struct dev_pm_ops cxd224x_pm_ops = { + .suspend = cxd224x_suspend, + .resume = cxd224x_resume, +}; +#endif + +static const struct i2c_device_id cxd224x_id[] = { + { CXD224X_DEVICE_NAME, 0 }, + { } +}; + +static struct of_device_id cxd224x_match_table[] = { + { .compatible = "sony,cxd224x", }, + { }, +}; + +static struct i2c_driver cxd224x_driver = { + .id_table = cxd224x_id, + .probe = cxd224x_probe, + .remove = cxd224x_remove, + .driver = { + .owner = THIS_MODULE, + .name = CXD224X_DEVICE_NAME, +#ifdef CONFIG_PM + .pm = &cxd224x_pm_ops, +#endif + .of_match_table = cxd224x_match_table, + }, +}; + +static int __init cxd224x_dev_init(void) +{ + return i2c_add_driver(&cxd224x_driver); +} +module_init(cxd224x_dev_init); + +static void __exit cxd224x_dev_exit(void) +{ + i2c_del_driver(&cxd224x_driver); +} +module_exit(cxd224x_dev_exit); + +MODULE_AUTHOR("Sony"); +MODULE_DESCRIPTION("NFC cxd224x driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/ldo_vibrator.c b/drivers/misc/ldo_vibrator.c new file mode 100644 index 0000000000000000000000000000000000000000..bafe453c0ac2c8b2d4d8cfe1942fe6c5b206087f --- /dev/null +++ b/drivers/misc/ldo_vibrator.c @@ -0,0 +1,230 @@ +/* + * Authors: Atsushi Iyogi + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum ldo_vibrator_state { + LDO_VIBRATOR_OFF, + LDO_VIBRATOR_ON, +}; + +static void ldo_vibrator_vib_set(struct ldo_vibrator_data *data, int on) +{ + dev_dbg(data->dev, "%s vibrator set state(%d)\n", __func__, on); + gpio_set_value(data->gpio, on); +} + +static void ldo_vibrator_vib_work(struct work_struct *work) +{ + struct ldo_vibrator_data *data = container_of(work, + struct ldo_vibrator_data, work); + + dev_dbg(data->dev, "%s vib state(%d)\n", __func__, data->state); + ldo_vibrator_vib_set(data, data->state); +} + +static enum hrtimer_restart ldo_vibrator_vib_timer(struct hrtimer *timer) +{ + struct ldo_vibrator_data *data = container_of(timer, + struct ldo_vibrator_data, + vib_timer); + + dev_dbg(data->dev, "%s: timer end\n", __func__); + data->state = LDO_VIBRATOR_OFF; + schedule_work(&data->work); + + return HRTIMER_NORESTART; +} + +static int ldo_vibrator_vib_get_time(struct timed_output_dev *dev) +{ + struct ldo_vibrator_data *data = container_of(dev, + struct ldo_vibrator_data, + timed_dev); + int ret = 0; + + if (hrtimer_active(&data->vib_timer)) { + ktime_t r = hrtimer_get_remaining(&data->vib_timer); + ret = (int)ktime_to_us(r); + } + return ret; +} + +static void ldo_vibrator_vib_enable(struct timed_output_dev *dev, int value) +{ + struct ldo_vibrator_data *data = container_of(dev, + struct ldo_vibrator_data, + timed_dev); + + mutex_lock(&data->lock); + hrtimer_cancel(&data->vib_timer); + + dev_dbg(data->dev, "%s: timer value(%d)\n", __func__, value); + if (value == 0) { + data->state = LDO_VIBRATOR_OFF; + } else { + data->state = LDO_VIBRATOR_ON; + hrtimer_start(&data->vib_timer, + ktime_set(value / MSEC_PER_SEC, + (value % MSEC_PER_SEC) * + NSEC_PER_MSEC), + HRTIMER_MODE_REL); + } + mutex_unlock(&data->lock); + schedule_work(&data->work); +} + +#ifdef CONFIG_PM +static int ldo_vibrator_suspend(struct device *dev) +{ + struct ldo_vibrator_data *data = dev_get_drvdata(dev); + + hrtimer_cancel(&data->vib_timer); + cancel_work_sync(&data->work); + /* turn-off vibrator */ + ldo_vibrator_vib_set(data, 0); + + return 0; +} + +#else +#define ldo_vibrator_suspend NULL +#endif + +static SIMPLE_DEV_PM_OPS(ldo_vibrator_pm_ops, ldo_vibrator_suspend, NULL); + +static int ldo_vibrator_get_gpio_data(struct device *dev, int *gpio_num) +{ + struct device_node *node; + int gpio; + enum of_gpio_flags flags; + + node = dev->of_node; + if (node == NULL) + goto error; + + gpio = of_get_gpio_flags(node, 0, &flags); + if (!gpio_is_valid(gpio)) { + dev_err(dev, "%s: invalid gpio %d\n", __func__, gpio); + goto error; + } + *gpio_num = gpio; + + return 0; +error: + return -ENODEV; +} + +static int ldo_vibrator_probe(struct platform_device *pdev) +{ + struct ldo_vibrator_data *data; + int alt_gpio; + int ret; + + ret = ldo_vibrator_get_gpio_data(&pdev->dev, &alt_gpio); + if (ret) + goto out; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto out; + } + + data->gpio = alt_gpio; + data->dev = &pdev->dev; + + mutex_init(&data->lock); + INIT_WORK(&data->work, ldo_vibrator_vib_work); + + hrtimer_init(&data->vib_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + data->vib_timer.function = ldo_vibrator_vib_timer; + + data->timed_dev.name = "vibrator"; + data->timed_dev.get_time = ldo_vibrator_vib_get_time; + data->timed_dev.enable = ldo_vibrator_vib_enable; + + ret = timed_output_dev_register(&data->timed_dev); + if (ret < 0) { + dev_err(data->dev, + "%s: register timed_output device failed\n", __func__); + goto out; + } + + dev_set_drvdata(data->dev, data); + + dev_info(data->dev, "%s: success\n", __func__); +out: + return ret; +} + +static int ldo_vibrator_remove(struct platform_device *pdev) +{ + struct ldo_vibrator_data *data = dev_get_drvdata(&pdev->dev); + + hrtimer_cancel(&data->vib_timer); + cancel_work_sync(&data->work); + ldo_vibrator_vib_set(data, 0); + timed_output_dev_unregister(&data->timed_dev); + mutex_destroy(&data->lock); + + return 0; +} + +static const struct of_device_id ldo_vibrator_of_match[] = { + { .compatible = "ldo-vibrator", }, + { } +}; +MODULE_DEVICE_TABLE(of, ldo_vibrator_ids); + +static struct platform_driver ldo_vibrator_driver = { + .driver = { + .name = LDO_VIBRATOR_NAME, + .owner = THIS_MODULE, + .pm = &ldo_vibrator_pm_ops, + .of_match_table = ldo_vibrator_of_match, + }, + .probe = ldo_vibrator_probe, + .remove = ldo_vibrator_remove, +}; + +static int __init ldo_vibrator_init(void) +{ + return platform_driver_register(&ldo_vibrator_driver); +} + +static void __exit ldo_vibrator_exit(void) +{ + platform_driver_unregister(&ldo_vibrator_driver); +} + +module_init(ldo_vibrator_init); +module_exit(ldo_vibrator_exit); + +MODULE_DESCRIPTION("LDO vibrator driver"); +MODULE_AUTHOR("Atsushi Iyogi"); +MODULE_LICENSE("GPLV2"); diff --git a/drivers/misc/mm_tuner/Kconfig b/drivers/misc/mm_tuner/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..5f5c51a84ec839ef66825b8c3bbfefe55b196b0c --- /dev/null +++ b/drivers/misc/mm_tuner/Kconfig @@ -0,0 +1,16 @@ +config MMTUNER_MN8855x + tristate "Socionext mm_tuner driver support" + ---help--- + This module adds support for wireless adapters based on + Socionext MN8855x chipset. + + If you choose to build a module, it'll be called mm_tuner. Say Y if + unsure. + +config MMTUNER_DEBUG + bool "Socionext MN8855x Debug message mode" + depends on MMTUNER_MN8855x + default n + ---help--- + MN8855x driver debug message mode. Say Y when you want to debug. + diff --git a/drivers/misc/mm_tuner/Makefile b/drivers/misc/mm_tuner/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0ecf8e1dbf67db0084f3cec22c80de2a90fec642 --- /dev/null +++ b/drivers/misc/mm_tuner/Makefile @@ -0,0 +1,162 @@ +############################################################################## +# Makefile for TUNER Driver +############################################################################## + +#driver name +ifndef DRV_NAME +DRV_NAME = mm_tuner +endif + +LOCAL_INC += $(src)/include +LOCAL_COMMON += $(src)/include_share + +subdir-ccflags-y += -I$(LOCAL_INC) +subdir-ccflags-y += -I$(LOCAL_COMMON) + +OBJS := src/tuner_drv.o +OBJS += src/tuner_drv_hw.o + +#PATH compile options +CONFIG_MMTUNER_DPATH=SPI +CONFIG_MMTUNER_CPATH=SPI + +ifeq ($(CONFIG_MMTUNER_DEBUG), y) + subdir-ccflags-y += -DDEBUG +endif +ifeq ($(CONFIG_MMTUNER_MN8855x), m) + subdir-ccflags-y += -fno-pic +endif +ifdef $(CONFIG_MMTUNER_I2CPARPORTX) + subdir-ccflags-y += -DTUNER_CONFIG_IRQ_PC_LINUX +endif +ifeq ($(CONFIG_MMTUNER_HOSTCPU), pandaboard) + subdir-ccflags-y += -DPANDABOARD +endif +ifeq ($(CONFIG_MMTUNER_HOSTCPU), dragon410c) + subdir-ccflags-y += -DDRAGON410C +endif +ifeq ($(CONFIG_NO_DEVICE_TREE), y) + subdir-ccflags-y += -DTUNER_CONFIG_NO_DEVICE_TREE +endif + +# +# SPI compile options +# CONFIG_MMTUNER_TSIF_SPI_EDGE : Use edge mode for SPI +# CONFIG_MMTUNER_TSIF_SI_EXT : Use Extend Read command for packet read +# CONFIG_MMTUNER_DIV_SPI_MSG : Use message separetion mode for SPI +# +ifeq ($(CONFIG_MMTUNER_TSIF_SPI_EDGE), y) + subdir-ccflags-y += -DTUNER_CONFIG_SPI_EDGE +endif +ifeq ($(CONFIG_MMTUNER_TSIF_SPI_EXT), y) + subdir-ccflags-y += -DTUNER_CONFIG_SPI_EXTREAD +endif +ifeq ($(CONFIG_MMTUNER_DIV_SPI_MSG), y) + OBJS += src/tuner_drv_hw_spi.o + subdir-ccflags-y += -DTUNER_CONFIG_SPI_DIVMSG +endif +ifeq ($(CONFIG_MMTUNER_SPI_BREAKCODE), y) + subdir-ccflags-y += -DTUNER_CONFIG_SPI_BREAKCODE +endif + + +ifeq ($(CONFIG_MMTUNER_DPATH), SDIO) + OBJS += src/tuner_drv_hw_sdio.o + subdir-ccflags-y += -DDPATH_SDIO +endif +ifeq ($(CONFIG_MMTUNER_DPATH), SPI) + OBJS += src/tuner_drv_hw_spi.o + subdir-ccflags-y += -DDPATH_SPI +endif +ifeq ($(CONFIG_MMTUNER_CPATH), I2C) + OBJS += src/tuner_drv_hw_i2c.o + subdir-ccflags-y += -DCPATH_I2C +endif +ifeq ($(CONFIG_MMTUNER_CPATH), SPI) + subdir-ccflags-y += -DCPATH_SPI +endif +ifeq ($(CONFIG_MMTUNER_CPATH), SDIO) + subdir-ccflags-y += -DCPATH_SDIO +endif + +#SPI performance measurement debug +#GP Get Packet +#DR Get DATAREADY +#subdir-ccflags-y += -DSPI_GP_MESURE_DEBUG +#subdir-ccflags-y += -DSPI_DR_MESURE_DEBUG + +# +# PID NULL FILTER +# +ifeq ($(CONFIG_MMTUNER_NULLFILTER), y) + subdir-ccflags-y += -DTUNER_CONFIG_PF_NULLFILTER +endif + +# +# BYTE ORDER CONFIGURATION. +# +ifeq ($(CONFIG_MMTUNER_MSBFIRST), y) + subdir-ccflags-y += -DTUNER_CONFIG_SLV_MSBFIRST +endif + +# +# DMA ALIGNMENT +# +ifdef CONFIG_MMTUNER_ALIGN + subdir-ccflags-y += -DTUNER_CONFIG_SPI_ALIGN=${CONFIG_MMTUNER_ALIGN} +endif + + +# +# AES compile options +# +# CONFIG_MMTUNER_AES = y : Use AES but does not check TS header of 1st packet +# CONFIG_MMTUNER_AES = c : Use AES and check TS header of 1st packet +# +ifeq ($(CONFIG_MMTUNER_AES), y) + OBJS += src/tuner_drv_hw_aes.o + subdir-ccflags-y += -DTUNER_CONFIG_AES_ENABLE +endif + +ifeq ($(CONFIG_MMTUNER_AES), c) + OBJS += src/tuner_drv_hw_aes.o + OBJS += src/aes_sample.o + subdir-ccflags-y += -DTUNER_CONFIG_AES_ENABLE + subdir-ccflags-y += -DTUNER_CONFIG_AES_TSCHK +endif + + +# +# GPIF compile options +# +# CONFIG_MMTUNER_DPATH = GPIF : Use GPIF for DPATH +# CONFIG_MMTUNER_CPATH = GPIF : Use GPIF for CPATH +# CONFIG_MMTUNER_TSIF_GPIF_DMA : Use DMA transfer for DPATH +# +ifeq ($(CONFIG_MMTUNER_DPATH), GPIF) + OBJS += src/gpif.o + OBJS += src/gpmc.o + OBJS += src/tuner_drv_hw_gpif.o + subdir-ccflags-y += -DDPATH_GPIF +endif +ifeq ($(CONFIG_MMTUNER_CPATH), GPIF) + subdir-ccflags-y += -DCPATH_GPIF +endif +ifeq ($(CONFIG_MMTUNER_TSIF_GPIF_DMA), y) + subdir-ccflags-y += -DTUNER_CONFIG_GPIF_DMA +endif + +# +# Addtional libaray path is here +# +ifdef CONFIG_MMTUNER_LIBS + subdir-ccflags-y += -I${CONFIG_MMTUNER_LIBS} +endif + + + +$(DRV_NAME)-objs += $(OBJS) + +obj-$(CONFIG_MMTUNER_MN8855x) = $(DRV_NAME).o + +clean-files := *.o .*.cmd modules.builtin modules.order diff --git a/drivers/misc/mm_tuner/include/tuner_drv.h b/drivers/misc/mm_tuner/include/tuner_drv.h new file mode 100644 index 0000000000000000000000000000000000000000..146cf343886fa8db4a42f5890710d42679aa1c8f --- /dev/null +++ b/drivers/misc/mm_tuner/include/tuner_drv.h @@ -0,0 +1,170 @@ +/***************************************************************************//** + * + * @file tuner_drv.h + * + * @brief common header file for mm_tuner55x driver + * + ****************************************************************************//* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + ******************************************************************************/ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +/*..+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...*/ +#ifndef _TUNER_DRV_H +#define _TUNER_DRV_H + +#ifdef DEBUG +#include +#define __file__ (strrchr(__FILE__, '/') + 1) +#else +#endif + +#include +#include +#include + +#include "tuner_drv_sys.h" + +/** + * Structure providing the version of the tuner driver runtime + */ +struct _mmtuner_version { + /** target device identifier + * + * Device id means two digits of bottom of type name. + */ + const uint8_t device; + + /** driver major version */ + const uint8_t major; + + /** driver minor version */ + const uint8_t minor; + + /** driver tinny version */ + const uint8_t hotfix; + + /** driver release candidate suffix string, e.g. "-rc4". */ + const char *rc; + + /** driver description */ + const char *describe; +}; + +/** + * MMTUNER context structure that contain some parameters and + * handle of the kernel threads. + */ +struct _mmtuner_cntxt { + /* wait queue for the poll/select system call */ + wait_queue_head_t poll_waitq; + /* exclusive control to access poll_flag */ + spinlock_t poll_lock; + /* status flag for poll/select */ + uint32_t poll_flag; + + /* ID of kernel thread that handle interrupts (IRQ) from tuner device */ + struct task_struct *irqth_id; + /* IRQ kernel thread wake up flag */ + uint32_t irqth_flag; + /* IRQ kernel thread wait queue */ + wait_queue_head_t irqth_waitq; + + /* to record the IRQ (event) factor */ + union _tuner_data_event ev; + + /* multiple open count */ + uint32_t opcnt; +}; + +struct _tsif_cntxt { + /* TS I/F Thread */ + struct task_struct *tsifth_id; /* Kernel thread ID */ + bool tsifth_wait; /* Wait indicator */ + uint32_t tsifth_flag; /* wake up flag */ + wait_queue_head_t tsifth_waitq; /* wait queue */ + + /* TS packet buffer */ + uint8_t *pktbuf; /* pointer to TS packet buffer */ + uint8_t *spibuf; /* pointer to SPI transfer*/ + uint32_t pwr; /* write position of TS packet buffer */ + uint32_t prd; /* read position of TS packet buffer */ + uint32_t ovf; /* packet buffer overflow counter */ + + enum _bw_seg bw; /* reception SEGment system */ + size_t ts_rxpkt_num; /* num of packets a RX transaction */ + size_t ts_rx_size; /* RX transaction byte size */ + size_t ts_pktbuf_size; /* TS receive buffer size */ + + /* read (TS data read) */ + uint32_t tsread_flag; /* wake up flag */ + wait_queue_head_t tsread_waitq; /* wait queue */ + + struct _tuner_data_tsif *tsif; +}; + +/* flag bit position of IRQ kernel thread */ +#define TUNER_IRQTH_NONE 0x00000000 /* initial flag */ +#define TUNER_IRQKTH_CATCHIRQ 0x00000001 /* interrupt flag position */ +#define TUNER_KTH_END 0x80000000 /* end flag position */ + +/* flag bit position of TS buffering thread */ +#define TUNER_TSIFTH_NONE 0x00000000 /* initial flag */ +#define TUNER_TSIFTH_ACTIVE 0x00000001 /* thread is working */ +#define TUNER_TSIFTH_END 0x80000000 /* end flag position */ + +#define TUNER_TSIFTH_FIFOERROR_MAX (10) + +/* TS I/F thread retry & wait time */ +#define TUNER_TSIFTH_SLEEP_RETRY (500) +#define TUNER_TSIFTH_SLEEP_MIN (1000) +#define TUNER_TSIFTH_SLEEP_MAX (2000) + +/* flag bit position of TS reading */ +#define TUNER_TSREAD_WAIT 0x00000000 /* wait */ +#define TUNER_TSREAD_IDLE 0x00000001 /* idle (initial) */ +#define TUNER_TSREAD_ACTIVE 0x00000002 /* active (reading) */ +#define TUNER_TSREAD_TIMEOUT 0x00000004 /* Timeout */ +#define TUNER_TSREAD_END 0x80000000 /* end */ + + +/* 4 : Use both IL=2 and IL=4 , then packet buffer is 1.0Mb (default)*/ +/* 2 : USE ONLY IL=2 , then expand packet buffer to 2.7Mb */ +/* Please set TUNER_TSPKTBUF_MODE to 2 +* when you don't need to Interleave mode 4 +*/ +#define TUNER_TSPKTBUF_MODE 4 + +/* Maximum packet buffer size is defined by MAX_TSPKTBUF_SIZE. +* Also it will be limited by MAX_TSPKTBUF_BANK. The size of +* packet buffer will be calculated by the below, +* maxbank = TUNER_MAX_TSPKTBUF_SIZE/lowerlimit; +* if ( maxbank > TUNER_MAX_TSPKTBUF_BANK ) maxbank = TUNER_MAX_TSPKTBUF_BANK; +* packet buffer size = tc->ts_rx_size) * maxbank; +*/ +#define TUNER_MAX_TSPKTBUF_SIZE 2097152 +#define TUNER_MAX_TSPKTBUF_BANK 12 + +extern irqreturn_t tuner_interrupt(int irq, void *dev_id); + +#endif /* _TUNER_DRV_H */ +/******************************************************************************* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************/ diff --git a/drivers/misc/mm_tuner/include/tuner_drv_hw.h b/drivers/misc/mm_tuner/include/tuner_drv_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..8ebcc829a5106d10754dac39119042df8e4dfdd0 --- /dev/null +++ b/drivers/misc/mm_tuner/include/tuner_drv_hw.h @@ -0,0 +1,127 @@ +/**************************************************************************//** + * + * @file tuner_drv_hw.h + * + * @brief Common header file of the HardWare control layer. + * + ***************************************************************************//* + * Copyright (c) 2015 Socionext Inc. + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + ******************************************************************************/ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +/*..+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...*/ +#ifndef _TUNER_DRV_HW_H +#define _TUNER_DRV_HW_H + +/****************************************************************************** + * include + ******************************************************************************/ +#include "tuner_drv.h" + +/****************************************************************************** + * prototype + ******************************************************************************/ + +/* following functions are described in "tuner_drv_hw.c" */ +int tuner_drv_hw_reqirq(void); +void tuner_drv_hw_freeirq(void); + +#ifdef TUNER_CONFIG_IRQ_LEVELTRIGGER + +void tuner_drv_hw_enable_interrupt(void); +void tuner_drv_hw_disable_interrupt(void); + +#endif + +/* + * following functions are described in "tuner_drv_.c" + */ +int tuner_drv_hw_read_reg( + enum _reg_bank bank, + uint8_t adr, + uint16_t len, + uint8_t *rd + ); +int tuner_drv_hw_write_reg( + enum _reg_bank bank, + uint8_t adr, + uint16_t len, + uint8_t *wd + ); +int tuner_drv_hw_rmw_reg( + enum _reg_bank bank, + uint8_t adr, + uint8_t mask, + uint8_t wd + ); +int tuner_drv_hw_setev(union _tuner_data_event *ev); +int tuner_drv_hw_relev(union _tuner_data_event *ev); + +#ifndef CPATH_I2C +int tuner_drv_hw_write_prg( + enum _reg_bank bank, + uint8_t adr, + uint16_t len, + uint8_t *wd + ); +#endif +#ifdef CPATH_I2C +int tuner_drv_hw_set_id(enum _tuner_cpathid cpath_id); +#endif +extern enum _tuner_cpathid cpath_id; + +/* + * following functions are described in "tuner_drv_hw_.c". + * is NOT "i2c". + */ +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) +int tuner_drv_hw_tsif_set_tpm(void); +int tuner_drv_hw_tsif_register(void); +void tuner_drv_hw_tsif_unregister(void); + +int tuner_drv_hw_tsif_set_cntxt(struct _tsif_cntxt *tc); +int tuner_drv_hw_tsif_config(struct _tsif_cntxt *tc); +int tuner_drv_hw_tsif_get_pkts(struct _tsif_cntxt *tc); +int tuner_drv_hw_tsif_get_dready(void); +int tuner_drv_hw_tsif_sync_pkt(void); + +/* +* Common Setting for slave IF +* These setting are only valid when DPATH is enabled. +*/ + +extern struct snglreg slvif_cfgregs[]; +/* register offset is below */ +#define SLVIF_CFG_SLVINTEN (0) +#define SLVIF_CFG_ISEGSEL (1) +#define SLVIF_CFG_DOSET4 (2) +#define SLVIF_CFG_WATERLINE (3) +#define SLVIF_CFG_BYTEORDER (4) +#define SLVIF_CFG_PKTSYNCC3 (5) +#define SLVIF_CFG_IFPWDSET1 (6) + +#endif + +extern int TUNER_CONFIG_INT; + +#endif /* _TUNER_DRV_HW_H */ +/******************************************************************************* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************/ diff --git a/drivers/misc/mm_tuner/include/version.h b/drivers/misc/mm_tuner/include/version.h new file mode 100644 index 0000000000000000000000000000000000000000..5d5df8484f449fbbf01173d4515215739dbbbbb7 --- /dev/null +++ b/drivers/misc/mm_tuner/include/version.h @@ -0,0 +1,60 @@ +/***************************************************************************//** + * + * @file version.h + * + * @brief define version of mm_tuner driver + * + ****************************************************************************//* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + ******************************************************************************/ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +/*..+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...*/ +#ifndef _MMTUNER_VERSION_H +#define _MMTUNER_VERSION_H + +#ifndef MMTUENR_DEVICE +#define MMTUNER_DEVICE (0x53) /*!< Target device id. (MN885xx) */ +#endif +#ifndef MMTUNER_MAJOR +#define MMTUNER_MAJOR (0) +#endif +#ifndef MMTUNER_MINOR +#define MMTUNER_MINOR (4) +#endif +#ifndef MMTUNER_HOTFIX +#define MMTUNER_HOTFIX (1) +#endif +/* + * MMTUNER_RC is the release candidate suffix. + * Should normally be empty. + */ +#ifndef MMTUNER_RC +#define MMTUNER_RC "" +#endif + +#ifndef MMTUNER_DESC +#define MMTUNER_DESC "" +#endif + +#endif +/******************************************************************************* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************/ diff --git a/drivers/misc/mm_tuner/include_share/tuner_drv_config.h b/drivers/misc/mm_tuner/include_share/tuner_drv_config.h new file mode 100644 index 0000000000000000000000000000000000000000..b5116c8100c4cda6db56375ff4df301ca1d57a64 --- /dev/null +++ b/drivers/misc/mm_tuner/include_share/tuner_drv_config.h @@ -0,0 +1,156 @@ +/**************************************************************************//** + * + * @file tuner_drv_config.h + * + * @brief configuration header of the mm_tuner55x driver + * + ****************************************************************************//* + * Copyright (c) 2015 Socionext Inc. + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + ******************************************************************************/ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +/*..+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...*/ +#ifndef _TUNER_DRV_CONFIG_H +#define _TUNER_DRV_CONFIG_H + +/****************************************************************************** + * define + ******************************************************************************/ +#define TUNER_SET_ON 1 /* setting ON */ +#define TUNER_SET_OFF 0 /* setting OFF */ + +/* device driver file name */ +#define TUNER_CONFIG_DRIVER_NAME "mmtuner" + +/* device number */ +#define TUNER_CONFIG_DRV_MAJOR 100 /* MAJOR No. */ +#define TUNER_CONFIG_DRV_MINOR 200 /* MINOR No. */ + +/* compile switch for IRQ */ +/* #define TUNER_CONFIG_IRQ_PC_LINUX */ + +/* IRQ */ +/* #define TUNER_CONFIG_IRQ_ENABLE */ /* System IRQ Enable */ +extern int TUNER_CONFIG_INT; + +/** + * IRQ kernel thread priority (0-99) + */ +#define TUNER_CONFIG_KTH_PRI 95 + +/* TS I/F kernel thread priority (0-99) */ +#define TUNER_CONFIG_TSBTH_PRI 95 + +/* exclusive access control */ +/* #define TUNER_CONFIG_DRV_MULTI */ + +/** + * @brief Compile switch for Device Tree. + * + * This definition should be enabled + * if the kernel does NOT support Device Tree. + */ +/* #define TUNER_CONFIG_NO_DEVICE_TREE */ + +/** + * @brief Compile switch for the SPI EDGE mode. + * + * Use SPI edge mode when using SPI slave I/F. + * Please define this macro TUNER_CONFIG_SPI_EDGE + * when you use 30MHz over SPI CLK. + */ +/* #define TUNER_CONFIG_SPI_EDGE */ + +/* @brief SPI calibration Timeout [ms]. */ +#define TUNER_CONFIG_CALIBRATION_TIMEOUT (1800000UL) + +/** + * @brief Compile switch for the SPI BREAK code at every SPI command. + * + * Send SPI BREAKCODE. + * Insert SPI break pattern before every SPI command when defined. + */ +/* #define TUNER_CONFIG_SPI_BREAKCODE */ + +/** + * @brief Compile switch for the SPI divide transaction mode. + * + * Divide SPI Packet Read command into 2 transactions + * (command phase and data phase). + */ +/* #define TUNER_CONFIG_SPI_DIV_MSG */ + +/** + * @brief Compile switch for the extend packet read mode. + * + * Use Extend Packet read with SPI slave I/F. + * We DON'T need to use this option usually. + */ +/* #define TUNER_CONFIG_SPI_EXTREAD */ + +/* @brief TS-Read timeout limit [ms]. */ +#define TUNER_CONFIG_TSREAD_TIMEOUT (1200UL) + + +/* Using DMA transfer when using GPIF I/F */ +/* #define TUNER_CONFIG_GPIF_DMA */ + +/* Enable AES on DPATH */ +/* #define TUNER_CONFIG_AES_ENABLE */ + +/* Enable TS packet when AES is on */ +/* #define TUNER_CONFIG_AES_TSCHK */ + +/* Enable PID NULL Packet filter */ +/* #define TUNER_CONFIG_PF_NULLFILTER */ + +/* Configurate byte order of TS stream via slave i/f */ +/* Plase set the following MACRO when you need the byte order transform */ +/* +-----------+------------+------------+-----------+------------* */ +/* | Slave | Size | MACRO | BYTEORDER | CPU ENDIAN | */ +/* +-----------+------------+------------+-----------+------------+ */ +/* | SPI Slave | 8 | Don't care | MSB First | BIG/LITTLE | */ +/* | SPI Slave | 32 | Undefined | LSB First | LITTLE | */ +/* | SPI Slave | 32 | Defined | MSB First | BIG | */ +/* +-----------+------------+------------+-----------+------------+ */ +/* | SDIO | Don't care | Don't care | MSB First | Don't care | */ +/* +-----------+------------+------------+-----------+------------+ */ +/* | GPIF | Don't care | Undefined | LSB First | Don't care | */ +/* | GPIF | Don't care | Defined | MSB First | Don't care | */ +/* +-----------+------------+------------+-----------+------------+ */ +/* LSB First Stream ( .. .. .. 0x47 .. .. ) */ +/* MSB First Stream ( 0x47 .. .. .. ) */ +/* The order of GPIF depends on memory controller */ +/* #define TUNER_CONFIG_SLV_MSBFIRST */ + + +/* DMA Boundary */ +/* Some SoC has the transfer size limitation to use DMA with SPI */ +/* It's limitation is that the data size must be align with 1K */ +/* So, when you want to use these SoC,please set the following MACRO */ +/* When SoC has 512byte boundary limitation,set to 512 */ +/* When SoC has 1024byte boundary limitation,set to 1024 */ +/* #define TUNER_CONFIG_SPI_ALIGN 1024 */ + + +#endif/* _TUNER_DRV_CONFIG_H */ +/******************************************************************************* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************/ diff --git a/drivers/misc/mm_tuner/include_share/tuner_drv_sys.h b/drivers/misc/mm_tuner/include_share/tuner_drv_sys.h new file mode 100644 index 0000000000000000000000000000000000000000..9ad47fda665e9869f930dc925e129b3637b15c35 --- /dev/null +++ b/drivers/misc/mm_tuner/include_share/tuner_drv_sys.h @@ -0,0 +1,179 @@ +/**************************************************************************//** + * + * @file tuner_drv_sys.h + * @brief The public header for the mm_tuner55x driver + * + ****************************************************************************//* + * Copyright (c) 2015 Socionext Inc. + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + ******************************************************************************/ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +/*..+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...*/ +#ifndef _TUNER_DRV_SYS_H +#define _TUNER_DRV_SYS_H + +/****************************************************************************** + * include + ******************************************************************************/ +#include "tuner_drv_config.h" + +/****************************************************************************** + * define + ******************************************************************************/ +/* IOCTL parameters */ +#define TUNER_IOC_MAGIC 'd' +#define TUNER_IOCTL_VALGET _IOWR(TUNER_IOC_MAGIC, 1, union _tuner_data_rw) +#define TUNER_IOCTL_VALSET _IOW(TUNER_IOC_MAGIC, 2, union _tuner_data_rw) +#define TUNER_IOCTL_EVENT_GET _IOWR(TUNER_IOC_MAGIC, 5, union _tuner_data_event) +#define TUNER_IOCTL_EVENT_SET _IOW(TUNER_IOC_MAGIC, 6, union _tuner_data_event) +#define TUNER_IOCTL_EVENT_REL _IOW(TUNER_IOC_MAGIC, 7, union _tuner_data_event) +#define TUNER_IOCTL_CNTSET _IOW(TUNER_IOC_MAGIC, 3, union _tuner_data_rw) +#define TUNER_IOCTL_CNTGET _IOWR(TUNER_IOC_MAGIC, 4, union _tuner_data_rw) +#define TUNER_IOCTL_TSIF_START _IOW(TUNER_IOC_MAGIC, 10,\ + struct _tuner_data_tsif) +#define TUNER_IOCTL_TSIF_STOP _IO(TUNER_IOC_MAGIC, 11) +#define TUNER_IOCTL_TSIF_PKTSIZE _IOR(TUNER_IOC_MAGIC, 12, unsigned int) +#define TUNER_IOCTL_GETVER _IOR(TUNER_IOC_MAGIC, 19, unsigned int) +#define TUNER_IOCTL_CPATHID _IOW(TUNER_IOC_MAGIC, 20, enum _tuner_cpathid) +#define TUNER_IOCTL_NRST_CTL _IOW(TUNER_IOC_MAGIC, 30, unsigned int) + +#define TUNER_IOCTL_TSIF_BLKSIZE _IOR(TUNER_IOC_MAGIC, 64, int) +#define TUNER_IOCTL_TSIF_GET_IV _IOR(TUNER_IOC_MAGIC, 65, uint8_t) +#define TUNER_IOCTL_TSIF_INIT_IV _IOW(TUNER_IOC_MAGIC, 66, uint8_t) + + +/****************************************************************************** + * enumerator type + ******************************************************************************/ +/** @addtogroup group_libtuner_API_public */ + +/** @brief Register bank enumerator */ +enum _reg_bank { + Sub = 0, /*!< Register bank in RF circuit */ + Main1 = 1, /*!< Register bank in the 13(full)-segment demodulator */ + Main2 = 2, /*!< Register bank in the 1-segment dedicated demodulator */ +#ifdef __KERNEL__ + SSub = 3, + SMain1 = 4, + SMain2 = 5, + END_SLVCFG = 255 /* End Mark */ +#endif +}; + +/** @brief Event (interrupt) setting mode */ +enum _evset_mode { + /** Add the specified event definition to existence definitions */ + TUNER_EVENT_MODE_ADD = 0, + /** Clear existence definitions and set specified definitions only */ + TUNER_EVENT_MODE_OVW = 1, +}; + +/** @brief OFDM demodulator circuit enumerators. */ +enum _bw_seg { + TUNER_DRV_BW13 = 0, /*!< 13(full)-seg. reception. */ + TUNER_DRV_BW1 = 1, /*!< 1-segment reception. */ + TUNER_DRV_BW3 = 2, /*!< 3-segment reception. */ +}; + +/** @brief TS packet type enumerator */ +enum _ts_pkt_type { + TUNER_DRV_TS_NORMAL = 0, /*!< 188 bytes length */ + TUNER_DRV_TS_ADDFEC = 1, /*!< 204 bytes length (with redundancy bits) */ + TUNER_DRV_TS_TSTAMP = 2, /*!< 192 bytes length (with Time-Stamp) */ +}; +/** @} */ +enum _tuner_cpathid { + DVR_MASTER = 0, + DVR_SLAVE = 3, +}; + +/****************************************************************************** + * struct/union type + ******************************************************************************/ +/* for register read/write */ +/* @brief Structure to write some (masked) bits of a register. */ +struct snglreg { + enum _reg_bank bank; /*!< Register bank. */ + uint8_t adr; /*!< Offset address in a bank. */ + uint8_t enabit; /*!< bit-mask specifies some bits of a register. */ + uint8_t param; /*!< read/write data. */ +}; + +union _tuner_data_rw { + struct snglreg sngl; + struct { + enum _reg_bank bank; /* reg. bank */ + uint8_t adr; /* reg. address */ + uint16_t len; /* continuous length */ + uint8_t *buf; /* buffer for continuous read/write */ + } cont; +}; + +/** @addtogroup group_libtuner_API_public */ + +/** @brief Union to set/get the event (interrupt) definitions/factors */ +union _tuner_data_event { + struct { + unsigned intst: 8; /*!< INTST register */ + unsigned intcnd: 8; /*!< INTCND register */ + unsigned intset1: 8; /*!< INTSET1 register */ + unsigned irqnum: 8; /*!< Num of the IRQ */ + } get; /*!< To access as the event (interrupt) factor */ + struct { + unsigned intdef2: 4; /*!< INTDEF2[3:0] register */ + unsigned reserve: 4; /*!< reserve bits */ + unsigned intdef1: 8; /*!< INTDEF1 register */ + unsigned intset1: 8; /*!< INTSET1 register */ + unsigned mode: 4; /*!< ::_evset_mode */ + unsigned reserve1: 4; /*!< reserve bits */ + } set; /*!< To access as the event (interrupt) definition */ + /** @brief For the Event Enumerator (::_tuner_event) */ + uint32_t pack; +}; + +/** @brief Event (interrupt) definition/factor type */ + +/** @brief TS slave I/F control parameters + * + * Control TS slave I/F sub-system of the tuner device. + */ +struct _tuner_data_tsif { + uint8_t dwind[3]; /*!< Data window width */ + uint8_t thl[3]; /*!< Water line lower threshold */ + + enum _ts_pkt_type ts_pkt_type; /*!< TS packet type */ + + /* AES configuration */ + uint8_t aes_mode; + + /* depend on the SPI (HOST-Master) I/F */ + uint8_t spi_ts_bit_per_word; /*!< Bits per a word of SPI I/F */ + /*1: calibration execute when tuner_drv_hw_tsif_get_pkts called. */ + /*0: calibration off. */ + uint8_t spi_calibration_flag; +}; +/** @brief TS slave I/F control type */ + +/** @} */ + +#endif/* _TUNER_DRV_SYS_H */ +/******************************************************************************* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************/ diff --git a/drivers/misc/mm_tuner/src/tuner_drv.c b/drivers/misc/mm_tuner/src/tuner_drv.c new file mode 100644 index 0000000000000000000000000000000000000000..5f8a3237ebe63c994197e539ad1f2705c3392002 --- /dev/null +++ b/drivers/misc/mm_tuner/src/tuner_drv.c @@ -0,0 +1,1952 @@ +/**************************************************************************//** + * + * @file tuner_drv.c + * + * @brief The implementation that is independence in physical I/F. + * + ***************************************************************************//* + * Copyright (c) 2015 Socionext Inc. + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + ******************************************************************************/ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +/*..+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...*/ + +/****************************************************************************** + * include + ******************************************************************************/ +#include "tuner_drv.h" +#include "tuner_drv_hw.h" +#include "version.h" + +#include +#include +#include +#include +#include +/* For Timeout procedure */ +#include +#include + +#if defined(DPATH_GPIF) +/* For DMA Mapping for gpif */ +#include +#endif + +#include +#include +#include +#include + +#define D_TUNER_POWER_ON_WAIT_US 10000 /* 10ms */ +#define D_TUNER_POWER_ON_WAIT_RANGE_US 10100 +#define D_TUNER_NRST_WAIT_US 10000 /* 10ms */ +#define D_TUNER_NRST_WAIT_RANGE_US 10100 +#define D_TUNER_WAIT_1SEG_MS 10 + +#define D_TUNER_CONFIG_PLATFORM_DRIVER_NAME "mmtuner_pdev" +#define D_TUNER_CONFIG_SYSFS_DEV_NAME "mmtuner_pdev" +#define D_TUNER_CONFIG_MATCH_TABLE "socionext,mn88553" + +enum gpio_id { + TUNER_POWER_PIN = 0, + TUNER_RESET_PIN, + TUNER_INT_PIN, +}; + +static char const * const gpio_rsrcs[] = { + "ISDB-T tuner power", + "ISDB-T tuner reset", + "ISDB-T tuner int", +}; + +enum TUNER_DRV_CTL { + TUNER_DRV_CTL_POWON, + TUNER_DRV_CTL_POWOFF +}; + +enum TUNER_DTV_SIG_LEVEL { + TUNER_DRV_SIG_L, + TUNER_DRV_SIG_H +}; + +struct tuner_drvdata { + struct device *dev; + struct device sysfs_dev; + struct mutex mutex_lock; + unsigned int gpios[ARRAY_SIZE(gpio_rsrcs)]; +}; + +struct g_tuner_device { + struct mutex g_tuner_mutex; + unsigned int gpios[ARRAY_SIZE(gpio_rsrcs)]; +}; +static struct g_tuner_device tnr_dev; + +static enum gpio_id req_ids[] = { + TUNER_POWER_PIN, + TUNER_RESET_PIN, + TUNER_INT_PIN, +}; + +/****************************************************************************** + * variables + ******************************************************************************/ + +/****************************************************************************** + * data + ******************************************************************************/ +static struct _mmtuner_cntxt g_cnt; /* mm_tuner driver context */ + +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) +static struct _tsif_cntxt g_tscnt; /* TS I/F context */ +#endif + +/** @brief TS packet size. + * + * Array index of this constant array is + * equivalent to ::_ts_pkt_type (enumeration type). + */ +static const size_t g_ts_pkt_size[3] = { 188, 204, 192 }; + +static const struct _mmtuner_version mmtuner_version = { + MMTUNER_DEVICE, + MMTUNER_MAJOR, MMTUNER_MINOR, MMTUNER_HOTFIX, + MMTUNER_RC, MMTUNER_DESC +}; + +enum _tuner_cpathid cpath_id = DVR_MASTER; +int TUNER_CONFIG_INT; + +/****************************************************************************** + * function + ******************************************************************************/ +static ssize_t tuner_module_entry_read(struct file *FIle, char __user *Buffer, + size_t Count, loff_t *OffsetPosition); +static ssize_t tuner_module_entry_write(struct file *FIle, + const char __user *Buffer, size_t Count, + loff_t *OffsetPosition); +#ifdef TUNER_CONFIG_IRQ_ENABLE +static unsigned int tuner_module_entry_poll(struct file *file, + struct poll_table_struct *poll_tbl); +#endif + +static long tuner_module_entry_ioctl(struct file *file, + unsigned int uCommand, + unsigned long uArgument); + +static int tuner_module_entry_open(struct inode *Inode, struct file *FIle); +static int tuner_module_entry_close(struct inode *Inode, struct file *FIle); +static int tuner_probe(struct platform_device *pdev); +static int __exit tuner_remove(struct platform_device *pdev); +static int tuner_pm_suspend(struct device *dev); +static int tuner_pm_resume(struct device *dev); +static int __init tuner_drv_start(void); +static void __exit tuner_drv_end(void); +#ifdef TUNER_CONFIG_IRQ_ENABLE +static int tuner_drv_irq_th(void *arc); +#endif +static int tuner_drv_read_regs(union _tuner_data_rw *rw, int num); +static int tuner_drv_write_regs(union _tuner_data_rw *rw, int num); + +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) +static int tuner_drv_tsif_set_cntxt(struct _tsif_cntxt *tc); +static inline int tuner_drv_bwseg(enum _bw_seg *pbw); +static int tuner_drv_tsif_start(void); +static int tuner_drv_tsif_stop(void); +static int tuner_drv_tsif_pktsize(void); +static int tuner_drv_tsif_blksize(void); +static int tuner_drv_tsif_th(void *arg); + +static void tsread_timer_handler(unsigned long data); +static struct timer_list tsread_timer; +#endif + +/* entry point */ +static const struct file_operations TunerFileOperations = { + .owner = THIS_MODULE, + .read = tuner_module_entry_read, + .write = tuner_module_entry_write, +#ifdef TUNER_CONFIG_IRQ_ENABLE + .poll = tuner_module_entry_poll, +#endif + .unlocked_ioctl = tuner_module_entry_ioctl, + .open = tuner_module_entry_open, + .release = tuner_module_entry_close +}; + +static const struct dev_pm_ops mmtuner_driver_pm_ops = { + .suspend = tuner_pm_suspend, + .resume = tuner_pm_resume, +}; + +static const struct of_device_id mn88553_match_table[] = { +{ .compatible = D_TUNER_CONFIG_MATCH_TABLE, +}, +{} +}; + +static struct platform_driver mmtuner_driver = { + .probe = tuner_probe, + .remove = __exit_p(tuner_remove), + .driver = { + .name = D_TUNER_CONFIG_PLATFORM_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mn88553_match_table), + } +}; + +static struct platform_device *mmtuner_device; +static struct class *device_class; + +/****************************************************************************** + * code area + ******************************************************************************/ + +static void dtv_tunerpm_power_control(struct tuner_drvdata *drvdata, int on) +{ + gpio_set_value_cansleep(drvdata->gpios[TUNER_POWER_PIN], on); +} + +static void dtv_tuner_reset_control(struct g_tuner_device *a_tnr_dev, + int on_off) +{ + gpio_set_value_cansleep(a_tnr_dev->gpios[TUNER_RESET_PIN], on_off); +} + +static int tuner_drv_ctl_reset(struct g_tuner_device *a_tnr_dev, int data) +{ + int ret = 0; + + pr_debug("%s,sig=%d\n", __func__, data); + + switch (data) { + /* reset */ + case TUNER_DRV_SIG_L: + mutex_lock(&a_tnr_dev->g_tuner_mutex); + dtv_tuner_reset_control(a_tnr_dev, 0); + mutex_unlock(&a_tnr_dev->g_tuner_mutex); + usleep_range(D_TUNER_NRST_WAIT_US, + D_TUNER_NRST_WAIT_RANGE_US); + break; + /* reset off*/ + case TUNER_DRV_SIG_H: + mutex_lock(&a_tnr_dev->g_tuner_mutex); + dtv_tuner_reset_control(a_tnr_dev, 1); + mutex_unlock(&a_tnr_dev->g_tuner_mutex); + usleep_range(D_TUNER_NRST_WAIT_US, + D_TUNER_NRST_WAIT_RANGE_US); + break; + default: + return -EINVAL; + } + return ret; +} + +static int tuner_drv_ctl_power(struct tuner_drvdata *drvdata, int data) +{ + int ret = 0; + + pr_debug("%s,data=%d\n", __func__, data); + + switch (data) { + case TUNER_DRV_CTL_POWON: + mutex_lock(&drvdata->mutex_lock); + dtv_tunerpm_power_control(drvdata, 1); + mutex_unlock(&drvdata->mutex_lock); +#ifdef CONFIG_CONTROL_NPDLOG + /* if npdlog is used, waiting is necessary. */ + usleep_range(D_TUNER_POWER_ON_WAIT_US, + D_TUNER_POWER_ON_WAIT_RANGE_US); +#endif + break; + + case TUNER_DRV_CTL_POWOFF: + mutex_lock(&drvdata->mutex_lock); + dtv_tunerpm_power_control(drvdata, 0); + mutex_unlock(&drvdata->mutex_lock); + break; + default: + return -EINVAL; + } + return ret; +} + +static int tunerpm_dev_init(struct platform_device *pdev, + struct tuner_drvdata *drvdata) +{ + int i, ret, gpio; + unsigned int flags; + struct device_node *of_node = pdev->dev.of_node; + + mutex_init(&drvdata->mutex_lock); + + for (i = 0; i < ARRAY_SIZE(gpio_rsrcs); i++) { + gpio = of_get_gpio_flags(of_node, i, &flags); + + pr_debug("%s,%d\n", __func__, gpio); + + if (!gpio_is_valid(gpio)) { + ret = -EINVAL; + goto error_gpio; + } + drvdata->gpios[i] = gpio; + tnr_dev.gpios[i] = gpio; + } + + for (i = 0; i < ARRAY_SIZE(req_ids); i++) { + + ret = gpio_request(drvdata->gpios[req_ids[i]], + gpio_rsrcs[req_ids[i]]); + + if (ret) + goto error_gpio_request; + } + + TUNER_CONFIG_INT = gpio_to_irq(drvdata->gpios[TUNER_INT_PIN]); + tuner_drv_ctl_reset(&tnr_dev, (int)TUNER_DRV_SIG_L); + tuner_drv_ctl_power(drvdata, TUNER_DRV_CTL_POWOFF); + + return 0; + +error_gpio_request: + for (i--; i >= 0; i--) + gpio_free(drvdata->gpios[req_ids[i]]); +error_gpio: + return ret; +} + +static ssize_t tuner_module_power_ctrl(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tuner_drvdata *drvdata = dev_get_drvdata(dev); + unsigned long value; + int ret; + + pr_debug("%s\n", __func__); + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (!value) { + ret = tuner_drv_ctl_power(drvdata, TUNER_DRV_CTL_POWON); + if (ret) + return -EINVAL; + } else { + tuner_drv_ctl_power(drvdata, TUNER_DRV_CTL_POWOFF); + } + + return count; +} + +static struct device_attribute tuner_sysfs_attrs[] = { + __ATTR(power_ctrl, S_IWUSR, 0, tuner_module_power_ctrl), +}; + +/**************************************************************************//** + * probe control of a driver + * + * @retval 0 normal + * @retval <0 error + * + * @param [in] pdev pointer to the structure "platform_device" + ******************************************************************************/ +static int tuner_probe(struct platform_device *pdev) +{ + int ret = 0, i, retval = 0; + struct tuner_drvdata *drvdata; + struct device *dev = NULL; + + pr_debug("%s-S,%p\n", __func__, pdev); + + /* memory allocation */ + mmtuner_device = platform_device_alloc(TUNER_CONFIG_DRIVER_NAME, -1); + + if (!mmtuner_device) { + pr_err("platform_device_alloc() failed.\n"); + return -ENOMEM; + } + + /* add device */ + ret = platform_device_add(mmtuner_device); + if (ret) { + pr_err("platform_device_add() failed.\n"); + retval = ret; + goto err_platform_device_add; + } + + /* create the node of device */ + device_class = class_create(THIS_MODULE, TUNER_CONFIG_DRIVER_NAME); + if (IS_ERR(device_class)) { + pr_err("class_create() failed.\n"); + retval = PTR_ERR(device_class); + goto err_class_create; + } + + /* create the logical device */ + dev = device_create(device_class, NULL, + MKDEV(TUNER_CONFIG_DRV_MAJOR, TUNER_CONFIG_DRV_MINOR), NULL, + TUNER_CONFIG_DRIVER_NAME); + if (IS_ERR(dev)) { + pr_err("device_create() failed.\n"); + retval = PTR_ERR(dev); + goto err_device_create; + } + + drvdata = kzalloc(sizeof(struct tuner_drvdata), GFP_KERNEL); + if (!drvdata) { + retval = -ENOMEM; + goto err_alloc_data; + } + + drvdata->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, drvdata); + drvdata->sysfs_dev.init_name = D_TUNER_CONFIG_SYSFS_DEV_NAME; + dev_set_drvdata(&drvdata->sysfs_dev, drvdata); + + ret = device_register(&drvdata->sysfs_dev); + if (ret) { + retval = -EINVAL; + goto err_set_dev; + } + + /* register the driver */ + if (register_chrdev(TUNER_CONFIG_DRV_MAJOR, TUNER_CONFIG_DRIVER_NAME, + &TunerFileOperations)) { + pr_err("register_chrdev() failed (Major:%d).\n", + TUNER_CONFIG_DRV_MAJOR); + retval = -EINVAL; + goto err_register_device; + } + + mutex_init(&tnr_dev.g_tuner_mutex); + ret = tunerpm_dev_init(pdev, drvdata); + if (ret) { + retval = -EINVAL; + goto out; + } + + for (i = 0; i < ARRAY_SIZE(tuner_sysfs_attrs); i++) { + ret = device_create_file(&drvdata->sysfs_dev, + &tuner_sysfs_attrs[i]); + if (ret) { + for (; i >= 0; --i) + device_remove_file(&drvdata->sysfs_dev, + &tuner_sysfs_attrs[i]); + retval = -EINVAL; + goto out; + } + } + +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + /* register the TS I/F driver */ + ret = tuner_drv_hw_tsif_register(); + if (ret) { + pr_err("tuner_drv_hw_tsif_register() failed.\n"); + retval = ret; + goto out; + } +#endif + + /* dispatch the kernel thread to handle the interrupt (IRQ) */ +#ifdef TUNER_CONFIG_IRQ_ENABLE + g_cnt.irqth_flag = TUNER_IRQTH_NONE; + init_waitqueue_head(&g_cnt.irqth_waitq); + g_cnt.irqth_id = kthread_create(tuner_drv_irq_th, NULL, + "tuner_drv_irq_th"); + if (IS_ERR(g_cnt.irqth_id)) { + retval = PTR_ERR(g_cnt.irqth_id); + g_cnt.irqth_id = NULL; + goto out; + } + + init_waitqueue_head(&g_cnt.poll_waitq); + spin_lock_init(&g_cnt.poll_lock); + g_cnt.poll_flag = 0x00; + + g_cnt.ev.pack = 0; + g_cnt.opcnt = 0; + + wake_up_process(g_cnt.irqth_id); +#endif + +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + /* dispatch a kernel thread to receive TS data */ + g_tscnt.tsifth_wait = true; + g_tscnt.tsifth_flag = TUNER_TSIFTH_NONE; + init_waitqueue_head(&g_tscnt.tsifth_waitq); + g_tscnt.tsifth_id = kthread_create(tuner_drv_tsif_th, NULL, + "tuner_drv_tsif_th"); + if (IS_ERR(g_tscnt.tsifth_id)) { + pr_err("kthread_create() failed.\n"); + retval = PTR_ERR(g_tscnt.tsifth_id); + g_tscnt.tsifth_id = NULL; + goto out; + } + + pr_debug("%s, kthread_create(tuner_drv_tsif_th)-after debug\n", + __func__); + + g_tscnt.pktbuf = NULL; + g_tscnt.spibuf = NULL; + g_tscnt.pwr = g_tscnt.prd = 0; + g_tscnt.ovf = 0; + + wake_up_process(g_tscnt.tsifth_id); + + /* initialize the status flag and + *the wait-queue for Ts Buffering Thread + */ + g_tscnt.tsread_flag = TUNER_TSREAD_IDLE; + init_waitqueue_head(&g_tscnt.tsread_waitq); +#endif + + pr_debug("%s-E\n", __func__); + return 0; + +out: + unregister_chrdev(TUNER_CONFIG_DRV_MAJOR, + TUNER_CONFIG_DRIVER_NAME); +err_register_device: + device_unregister(&drvdata->sysfs_dev); +err_set_dev: + kzfree(drvdata); +err_alloc_data: + device_destroy(device_class, MKDEV(TUNER_CONFIG_DRV_MAJOR, + TUNER_CONFIG_DRV_MINOR)); +err_device_create: + class_destroy(device_class); +err_class_create: + platform_device_del(mmtuner_device); +err_platform_device_add: + platform_device_put(mmtuner_device); + return retval; +} + +/**************************************************************************//** + * remove control of a driver + * + * @retval 0 normal + * @retval <0 error + * + * @param [in] pdev pointer to the structure "platform_device" + ******************************************************************************/ +static int __exit tuner_remove(struct platform_device *pdev) +{ + pr_debug("%s\n", __func__); + + /* release interrupt (IRQ) */ + tuner_drv_hw_freeirq(); + + /* un-register driver */ + unregister_chrdev(TUNER_CONFIG_DRV_MAJOR, TUNER_CONFIG_DRIVER_NAME); + + return 0; +} + +/*************************************************************************//*** + * suspend control of a driver + * + * @retval 0 normal + * @retval <0 error + * + * @param [in] dev device + ******************************************************************************/ +static int tuner_pm_suspend(struct device *dev) +{ + pr_debug("%s\n", __func__); + + return 0; +} + +/*************************************************************************//*** + * resume control of a driver + * + * @retval 0 normal + * @retval <0 error + * + * @param [in] dev device + ******************************************************************************/ +static int tuner_pm_resume(struct device *dev) +{ + int ret = 0; + + pr_debug("%s\n", __func__); + +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + ret = tuner_drv_hw_tsif_set_tpm(); + if (ret) { + pr_err("write TPM bits failed.\n"); + return ret; + } +#endif + return ret; +} + +/**************************************************************************//** + * Interrupt handling thread function + * + * @retval 0 normal + * @retval <0 error + * + * @param [in] arg (no effect) + ******************************************************************************/ +#ifdef TUNER_CONFIG_IRQ_ENABLE +static int tuner_drv_irq_th(void *arg) +{ + int ret = 0; + unsigned long flags; + unsigned long kthread_flg; + + mm_segment_t oldfs; + struct sched_param param; + + uint8_t buf[2] = { 0x00, 0x00 }; + + pr_debug("%s\n", __func__); + + /* initialize inner values */ + ret = 0; + flags = 0; + kthread_flg = 0; + param.sched_priority = TUNER_CONFIG_KTH_PRI; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + ret = sched_setscheduler(g_cnt.irqth_id, SCHED_FIFO, ¶m); + set_fs(oldfs); + + while (1) { + buf[0] = buf[1] = 0; + + pr_debug("%s waiting...\n", __func__); + wait_event_interruptible(g_cnt.irqth_waitq, g_cnt.irqth_flag); + + spin_lock_irqsave(&g_cnt.poll_lock, flags); + kthread_flg = g_cnt.irqth_flag; + g_cnt.irqth_flag &= ~TUNER_IRQKTH_CATCHIRQ; + spin_unlock_irqrestore(&g_cnt.poll_lock, flags); + + if ((kthread_flg & TUNER_IRQKTH_CATCHIRQ) == + TUNER_IRQKTH_CATCHIRQ) { + /* receive IRQ */ + pr_debug("%s IRQHANDLER start\n", __func__); + + /* Read INTCND, INTST */ + ret = tuner_drv_hw_read_reg( + Main1, + 0xE3, + 2, + buf); + if (ret) { + pr_err("Read IRQ factor/state, failed.\n"); + kthread_flg |= TUNER_KTH_END; + } + /* write (back) INTCND to clear + * the factor (register) of interrupt (IRQ) + */ + ret = tuner_drv_hw_write_reg( + Main1, + 0xE3, + 1, + buf); + if (ret) { + pr_err("Clear IRQ factor, failed."); + kthread_flg |= TUNER_KTH_END; + } + + g_cnt.ev.get.intcnd |= buf[0]; + g_cnt.ev.get.intst |= buf[1]; + g_cnt.ev.get.irqnum++; + + pr_debug("IRQ factor update (%d): INTCND:0x%02x INTST:0x%02x\n", + g_cnt.ev.get.irqnum, g_cnt.ev.get.intcnd, + g_cnt.ev.get.intst); + + /* release poll/select */ + g_cnt.poll_flag = 0x01; + wake_up(&g_cnt.poll_waitq); + + pr_debug("%s main loop go to next turn.\n", __func__); + +#ifdef TUNER_CONFIG_IRQ_LEVELTRIGGER + /* activate (re-activate) the interrupt, + *if the level-interrupt is active + */ + tuner_drv_hw_enable_interrupt(); +#endif /* TUNER_CONFIG_IRQ_LEVELTRIGGER */ + } + + /* request to finish the interrupt kernel thread */ + if ((kthread_flg & TUNER_KTH_END) == TUNER_KTH_END) { + pr_debug("%s caught a stop request.\n", __func__); + + spin_lock_irqsave(&g_cnt.poll_lock, flags); + g_cnt.irqth_flag &= ~TUNER_KTH_END; + spin_unlock_irqrestore(&g_cnt.poll_lock, flags); + + break; + } + } + + pr_debug("Tail of thread function %s.\n", __func__); + return 0; +} +#endif + +/**************************************************************************//** + * initialization control of a driver + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +static int __init tuner_drv_start(void) +{ + int ret = 0; + + pr_debug("%s-S\n", __func__); + + pr_debug("mmtuner (for MN885%02x) ver. %d.%d.%d %s (%s)\n", + mmtuner_version.device, mmtuner_version.major, + mmtuner_version.minor, mmtuner_version.hotfix, + mmtuner_version.rc, mmtuner_version.describe); + + /* register "mmtuner" driver */ + ret = platform_driver_register(&mmtuner_driver); + if (ret != 0) { + pr_err("platform_driver_register failed.\n"); + return ret; + } + + pr_debug("%s-E\n", __func__); + + return 0; /* normal */ +} + +/**************************************************************************//** + * exit control of a driver + * + ******************************************************************************/ +static void __exit tuner_drv_end(void) +{ + pr_debug("%s\n", __func__); + +#ifdef TUNER_CONFIG_IRQ_ENABLE + g_cnt.irqth_flag |= TUNER_KTH_END; + /* exit the kernel thread (for IRQ) */ + if (waitqueue_active(&g_cnt.irqth_waitq)) + wake_up(&g_cnt.irqth_waitq); + + /* unregister the IRQ kernel thread */ + if (g_cnt.irqth_id) + kthread_stop(g_cnt.irqth_id); +#endif + +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + g_tscnt.tsifth_flag = TUNER_TSIFTH_END; + /* exit the kernel thread (for TS) */ + if (waitqueue_active(&g_tscnt.tsifth_waitq)) + wake_up_interruptible(&g_tscnt.tsifth_waitq); + + g_tscnt.tsifth_wait = true; + + /* unregister the TS kernel thread */ + if (g_tscnt.tsifth_id) + kthread_stop(g_tscnt.tsifth_id); + + /* execute the unregister scheme of TS I/F */ + tuner_drv_hw_tsif_unregister(); +#endif + + /* Destroy device */ + device_destroy(device_class, + MKDEV(TUNER_CONFIG_DRV_MAJOR, TUNER_CONFIG_DRV_MINOR)); + /* delete a entry of class */ + class_destroy(device_class); + /* unregister the driver */ + platform_device_unregister(mmtuner_device); + /* unregister the platform entry */ + platform_driver_unregister(&mmtuner_driver); + +} + +/**************************************************************************//** + * open control of a driver + * + * @retval 0 normal + * @retval <0 error + * + * @param [in] Inode, FIle + ******************************************************************************/ +static int tuner_module_entry_open(struct inode *Inode, struct file *FIle) +{ + pr_debug("%s\n", __func__); + +#ifndef TUNER_CONFIG_DRV_MULTI + if (g_cnt.opcnt > 0) { + pr_err("It's being used.\n"); + return -EBUSY; + } +#endif /* TUNER_CONFIG_DRV_MULTI */ + + g_cnt.opcnt++; + pr_debug("user count: %d\n", g_cnt.opcnt); + + return 0; +} + +/**************************************************************************//** + * close control of a driver + * + * @retval 0 normal + * @retval <0 error + * + * @param [in] Inode, FIle regular argument for linux system call + ******************************************************************************/ +static int tuner_module_entry_close(struct inode *Inode, struct file *FIle) +{ + struct devone_data *dev; + + pr_debug("%s\n", __func__); + + if (g_cnt.opcnt == 0) { /* not open */ + pr_err("NOT IN USE.\n"); + return -ENODEV; + } + g_cnt.opcnt--; + + if (g_cnt.opcnt == 0) { /* All logical device is closed. */ + /* free IRQ */ + tuner_drv_hw_freeirq(); + if (FIle == NULL) + return -EINVAL; + dev = FIle->private_data; + kfree(dev); + } + + return 0; +} + +/**************************************************************************//** + * @brief "read" system call of mm_tuner device + * + * The "read" system-call acquires the TS data stream of + * the designated byte size. + * + * @retval >=0 normal (byte size) + * @retval <0 error + ******************************************************************************/ +static ssize_t tuner_module_entry_read(struct file *FIle, char __user *Buffer, + size_t Count, loff_t *OffsetPosition) +{ +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + ssize_t size = 0; + int ret; + int copy_size; + + if (!Buffer) { + pr_err("arg. \"Buffer\" is Null\n"); + return -EINVAL; + } + if (Count <= 0) { + pr_err("arg. \"Count\" is illegal (%zu)\n", Count); + return -EINVAL; + } + + if (g_tscnt.tsifth_wait) { + pr_warn("TS I/F thread is NOT active (waiting...)\n"); + return -EAGAIN; + } + if (g_tscnt.tsread_flag != TUNER_TSREAD_IDLE) { + pr_warn("read (TS) system call is executed in duplicate flag:%d\n", + g_tscnt.tsread_flag); + return -EBUSY; + } + g_tscnt.tsread_flag = TUNER_TSREAD_ACTIVE; + + /* clear the over-flow flag of the packet buffer */ + g_tscnt.ovf = 0; + + do { + int able_size = 0; + + /* TS FIFO is empty */ + if (g_tscnt.prd == g_tscnt.pwr) { + /* TS-Read timer */ + init_timer(&tsread_timer); + tsread_timer.expires = jiffies + + msecs_to_jiffies(TUNER_CONFIG_TSREAD_TIMEOUT); + tsread_timer.data = (unsigned long)jiffies; + tsread_timer.function = tsread_timer_handler; + add_timer(&tsread_timer); + + g_tscnt.tsread_flag = TUNER_TSREAD_WAIT; + usleep_range(100, 500); + wait_event_interruptible(g_tscnt.tsread_waitq, + g_tscnt.tsread_flag); + + del_timer(&tsread_timer); + if (g_tscnt.tsread_flag != TUNER_TSREAD_IDLE) { + pr_warn("Stop reading TS data.\n"); + pr_debug("TS-Read status flag: 0x%08x.\n", + g_tscnt.tsread_flag); + break; + } + g_tscnt.tsread_flag = TUNER_TSREAD_ACTIVE; + continue; + } + + /* readable data size of TS FIFO */ + able_size = (g_tscnt.pwr > g_tscnt.prd) ? + (g_tscnt.pwr - g_tscnt.prd) : + (g_tscnt.ts_pktbuf_size - g_tscnt.prd); + + /* decide copy_size */ + copy_size = ((size + able_size) > Count) ? + (Count - size) : + able_size; + ret = copy_to_user( + Buffer + size, + g_tscnt.pktbuf + g_tscnt.prd, + copy_size); + if (ret) { + pr_err("copy_to_user() failed.\n"); + return -EFAULT; + } + + /* increment read position */ + g_tscnt.prd += copy_size; + if (g_tscnt.prd == g_tscnt.ts_pktbuf_size) + g_tscnt.prd = 0; + + /* increment total copied size */ + size += copy_size; + + } while (size != Count); + + g_tscnt.tsread_flag = TUNER_TSREAD_IDLE; + + return size; +#else + pr_warn("NOT support the TS Slave I/F of the tuner device.\n"); + return -EIO; +#endif +} + +/**************************************************************************//** + * write control of a driver + * + * @caution The previous version of mm_tuner driver have "write" + * system call to write registers continuously. + * But, ioctl(TUNER_IOCTL_CNTSET) is implemented in this + * version. + * + * @retval 0 normal + * @retval -ENOSYS (not implemented) + * + * @param [in] FIle, Buffer, Count, OffsetPosition + * These are regular argument of the system call "write" + ******************************************************************************/ +static ssize_t tuner_module_entry_write(struct file *FIle, + const char __user *Buffer, size_t Count, loff_t *OffsetPosition) +{ + pr_warn("The \"write\" system-call is not supported.\n"); + return -EIO; +} + +/**************************************************************************//** + * ioctl system call + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +static long tuner_module_entry_ioctl(struct file *file, + unsigned int uCommand, unsigned long uArgument) +{ + int ret = 0; + int retval = 0; + union _tuner_data_rw rw; + union _tuner_data_event ev; + uint8_t *buf; + uint32_t ver; + uint8_t data; +#if defined(CPATH_I2C) + enum _tuner_cpathid cid; +#endif + unsigned int sig = 0; + + pr_debug("[IOCTL(uCommand): %x]\n", uCommand); + + switch (uCommand) { + /* get a parameter of the register of Tuner */ + case TUNER_IOCTL_VALGET: + if (copy_from_user(&rw, + (union _tuner_data_rw __user *)uArgument, + sizeof(union _tuner_data_rw))) { + pr_err("copy_from_user() failed.\n"); + return -EFAULT; + } + ret = tuner_drv_read_regs(&rw, 1); + if (!ret) { + if (copy_to_user( + (union _tuner_data_rw __user *)uArgument, &rw, + sizeof(union _tuner_data_rw))) { + pr_err("copy_to_user() failed.\n"); + return -EFAULT; + } + } else { + pr_err("read a register, failed.\n"); + return ret; + } + return 0; + /* write a parameters to the register of Tuner */ + case TUNER_IOCTL_VALSET: + if (copy_from_user(&rw, + (union _tuner_data_rw __user *)uArgument, + sizeof(union _tuner_data_rw))) { + pr_err("copy_from_user() failed.\n"); + return -EFAULT; + } + ret = tuner_drv_write_regs(&rw, 1); + if (ret) { + pr_err("write a register, failed.\n"); + return ret; + } + return 0; + /* write registers continuously */ + case TUNER_IOCTL_CNTSET: + if (copy_from_user(&rw, + (union _tuner_data_rw __user *)uArgument, + sizeof(union _tuner_data_rw))) { + pr_err("copy_from_user() failed.\n"); + return -EFAULT; + } + buf = kmalloc(rw.cont.len, GFP_KERNEL); + if (!buf) { + pr_err("memory allocation failed(CNTSET).\n"); + return -ENOMEM; + } + if (copy_from_user(buf, (void __user *)rw.cont.buf, + rw.cont.len)) { + pr_err("copy_from_user() failed.\n"); + retval = -EFAULT; + } else { +#if defined(CPATH_SPI) || defined(CPATH_SDIO) || defined(CPATH_GPIF) + if ((rw.cont.adr == 0xF6) && ((rw.cont.bank == 0) || + (rw.cont.bank == 2))) { + ret = tuner_drv_hw_write_prg(rw.cont.bank, + rw.cont.adr, rw.cont.len, buf); + if (ret) { + pr_err("write program continuously, failed.\n"); + retval = ret; + } + } else { +#endif + ret = tuner_drv_hw_write_reg((int)rw.cont.bank + + (int)cpath_id, rw.cont.adr, + rw.cont.len, buf); + if (ret) { + pr_err("write continuously, failed.\n"); + retval = ret; + } +#if defined(CPATH_SPI) || defined(CPATH_SDIO) || defined(CPATH_GPIF) + } +#endif + } + kfree(buf); + return retval; + /* read registers continuously */ + case TUNER_IOCTL_CNTGET: + if (copy_from_user(&rw, + (union _tuner_data_rw __user *)uArgument, + sizeof(union _tuner_data_rw))) { + pr_err("copy_from_user() failed.\n"); + return -EFAULT; + } + buf = kmalloc(rw.cont.len, GFP_KERNEL); + if (!buf) { + pr_err("memory allocation failed(CNTGET).\n"); + return -ENOMEM; + } + ret = tuner_drv_hw_read_reg((int)rw.cont.bank + + (int)cpath_id, rw.cont.adr, rw.cont.len, buf); + if (ret) { + pr_err("read continuously, failed.\n"); + retval = ret; + } else { + if (copy_to_user((void __user *)rw.cont.buf, + buf, rw.cont.len)) { + pr_err("copy_to_user() failed.\n"); + retval = -EFAULT; + } + } + kfree(buf); + return retval; + /* get the interrupt factor and status */ + case TUNER_IOCTL_EVENT_GET: + if (copy_to_user((union _tuner_data_event __user *)uArgument, + &g_cnt.ev, + sizeof(union _tuner_data_event))) { + pr_err("copy_to_user() failed.\n"); + return -EFAULT; + } + pr_debug("IRQ factor send: intset1:0x%02x intcnd:0x%02x intst:0x%02x\n", + g_cnt.ev.get.intset1, g_cnt.ev.get.intcnd, g_cnt.ev.get.intst); + + /* initialize the variables for the interrupt information */ + g_cnt.ev.pack = 0; + return 0; + /* be available some interrupts */ + case TUNER_IOCTL_EVENT_SET: + pr_debug("*** VALSET_EVENT ***\n"); + if (copy_from_user(&ev, + (union _tuner_data_event __user *)uArgument, + sizeof(union _tuner_data_event))) { + pr_err("copy_from_user() failed.\n"); + return -EFAULT; + } + ret = tuner_drv_hw_setev(&ev); + if (ret) { + pr_err("tuner_drv_setev() failed.\n"); + return ret; + } + return 0; + /* be disable some interrupts */ + case TUNER_IOCTL_EVENT_REL: + if (copy_from_user(&ev, + (union _tuner_data_event __user *)uArgument, + sizeof(union _tuner_data_event))) { + pr_err("copy_from_user() failed.\n"); + return -EFAULT; + } + ret = tuner_drv_hw_relev(&ev); + if (ret) { + pr_err("tuner_drv_relev() failed.\n"); + return ret; + } + return 0; + + /* start to receive TS data from Tuner */ + case TUNER_IOCTL_TSIF_START: +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + if (!g_tscnt.tsifth_wait) { + pr_warn("TS data buffering had already been started.\n"); + return -EBUSY; + } + if (g_tscnt.tsif != NULL) { + kfree(g_tscnt.tsif); + g_tscnt.tsif = NULL; + } + g_tscnt.tsif = + kmalloc(sizeof(struct _tuner_data_tsif), GFP_KERNEL); + if (g_tscnt.tsif == NULL) + return -ENOMEM; + if (copy_from_user(g_tscnt.tsif, + (struct _tuner_data_tsif __user *)uArgument, + sizeof(struct _tuner_data_tsif))) { + pr_err("copy_from_user() failed.\n"); + retval = -EFAULT; + } else { + ret = tuner_drv_tsif_start(); + if (ret) { + pr_err("tuner_drv_tsif_start() failed.\n"); + retval = ret; + } else { + return 0; + } + } + kfree(g_tscnt.tsif); + g_tscnt.tsif = NULL; + return retval; +#else + return -EINVAL; +#endif + /* stop to receive TS data from Tuner */ + case TUNER_IOCTL_TSIF_STOP: +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + return tuner_drv_tsif_stop(); +#else + return -EINVAL; +#endif + /* return byte num of a TS packet */ + case TUNER_IOCTL_TSIF_PKTSIZE: +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + ret = tuner_drv_tsif_pktsize(); + if (ret < 0) { + pr_err("tuner_drv_tsif_pktsize() failed.\n"); + return ret; + } + if (copy_to_user((unsigned int __user *)uArgument, + &ret, sizeof(unsigned int))) { + pr_err("copy_to_user() failed.\n"); + return -EFAULT; + } + return 0; +#else + pr_info("NOT support the TS Slave I/F of the tuner device.\n"); + return -EINVAL; +#endif + case TUNER_IOCTL_GETVER: + ver = (mmtuner_version.device << 24) | + (mmtuner_version.major << 16) | + (mmtuner_version.minor << 8) | + mmtuner_version.hotfix; + put_user(ver, (unsigned int __user *)uArgument); + + ret = tuner_drv_hw_read_reg(Sub, 0xFF, 1, &data); + if (ret) { + pr_err("Read CHIPID, failed.\n"); + return -EFAULT; + } + if (data != MMTUNER_DEVICE) { + pr_err("Unexpected CHIPRD (0x%02x).\n", data); + return -ENXIO; + } + return 0; + case TUNER_IOCTL_TSIF_BLKSIZE: +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + ret = tuner_drv_tsif_blksize(); + if (ret < 0) { + pr_err("tuner_drv_tsif_blksize() failed.\n"); + return ret; + } + if (copy_to_user((int __user *)uArgument, &ret, sizeof(int))) { + pr_err("copy_to_user() failed.\n"); + return -EFAULT; + } + return 0; +#else + pr_info("NOT support the TS Slave I/F of the tuner device.\n"); + return -EINVAL; +#endif + case TUNER_IOCTL_TSIF_GET_IV: { + pr_info("NOT support the TS Slave I/F of the tuner device.\n"); + return -EINVAL; + } + case TUNER_IOCTL_TSIF_INIT_IV: { + pr_info("NOT support the TS encryption mode\n"); + return -EINVAL; + } + case TUNER_IOCTL_CPATHID: +#ifdef CPATH_I2C + if (copy_from_user(&cid, + (enum _tuner_cpathid __user *)uArgument, + sizeof(enum _tuner_cpathid))) { + pr_err("copy_from_user() failed.\n"); + return -EFAULT; + } + ret = tuner_drv_hw_set_id(cid); + if (ret) { + pr_err("set id, failed.\n"); + retval = ret; + } + return retval; +#else + return -EINVAL; +#endif + /* write a SIG to the nrst of Tuner */ + case TUNER_IOCTL_NRST_CTL: + + if (copy_from_user(&sig, (unsigned int __user *)uArgument, + sizeof(unsigned int))) { + pr_err("copy_from_user() failed.\n"); + return -EFAULT; + } + + ret = tuner_drv_ctl_reset(&tnr_dev, (int)sig); + + if (ret) { + pr_err("write a nrst, failed.\n"); + return ret; + } + return 0; + + /* return byte num of a TS packet */ + default: + pr_err("illegal ioctl request.\n"); + return -EINVAL; + } +} + +/**************************************************************************//** + * poll control of a driver + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +#ifdef TUNER_CONFIG_IRQ_ENABLE +static unsigned int tuner_module_entry_poll(struct file *file, + struct poll_table_struct *poll_tbl) +{ + unsigned long tuner_flags; + unsigned int tuner_mask; + + /* initialize */ + tuner_mask = 0; + + /* wait */ + poll_wait(file, &g_cnt.poll_waitq, poll_tbl); + + /* disable the interrupt */ + spin_lock_irqsave(&g_cnt.poll_lock, tuner_flags); + + /* release */ + if (g_cnt.poll_flag == 0x01) + tuner_mask = (POLLIN | POLLRDNORM); + + g_cnt.poll_flag = 0x00; + + /* enable the interrupt */ + spin_unlock_irqrestore(&g_cnt.poll_lock, tuner_flags); + + return tuner_mask; +} +#endif + +/**************************************************************************//** + * interrupt control of a driver + * + * @retval IRQ_NONE interrupt was not from this device + * @retval IRQ_HANDLED interrupt was handled by this device + * @retval IRQ_WAKE_THREADhandler requests to wake the handler + * thread + * + * @param [in] irq irq# + * @parma [in] dev_id device ID + ******************************************************************************/ +#ifdef TUNER_CONFIG_IRQ_ENABLE +irqreturn_t tuner_interrupt(int irq, void *dev_id) +{ + pr_debug("%s\n", __func__); + + g_cnt.irqth_flag |= TUNER_IRQKTH_CATCHIRQ; + /* The main scheme for IRQ is in the IRQ kernel thread. + * Here is the wake up operation, only. + */ + if (waitqueue_active(&g_cnt.irqth_waitq)) { +#ifdef TUNER_CONFIG_IRQ_LEVELTRIGGER + /* disabling IRQ, when the level interrupt is avail. */ + tuner_drv_hw_disable_interrupt(); +#endif /* TUNER_CONFIG_IRQ_LEVELTRIGGER */ + wake_up(&g_cnt.irqth_waitq); + } else { + pr_err("waitqueue_active() failed.\n"); + /* When the wake-up scheme don't work, stop the receiving IRQ */ + } + + return IRQ_HANDLED; +} +#endif + +/**************************************************************************//** + * @brief Read some registers. + * + * Repeat single read transaction. + * + * @param [in] arg Address to a argument of ioctl() in unsigned long. + * @num [in] num Repeat count. + * + * @returns 0 on success. + * @returns Negative on error. + ******************************************************************************/ +static int tuner_drv_read_regs(union _tuner_data_rw *rw, int num) +{ + int i; + int ret; + + for (i = 0; i < num; i++) { + ret = tuner_drv_hw_read_reg( + rw[i].sngl.bank + (int)cpath_id, + rw[i].sngl.adr, + 1, + &(rw[i].sngl.param)); + if (ret) { + pr_err("copy_to_user() failed.\n"); + return ret; + } + } + return 0; +} + +/**************************************************************************//** + * write some registers of the tuner device. + * + * (no description) + * + * @retval 0 normal + * @retval -EINVAL error + ******************************************************************************/ +static int tuner_drv_write_regs(union _tuner_data_rw *rw, int num) +{ + int i; + int ret; + + for (i = 0; i < num; i++) { + ret = tuner_drv_hw_rmw_reg( + rw->sngl.bank + (int)cpath_id, + rw->sngl.adr, + rw->sngl.enabit, + rw->sngl.param); + if (ret) + return ret; + } + + return 0; +} + +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) +/**************************************************************************//** + * TS I/F (buffering) thread function + * + * @caption + * Original is "tuner_tsbufferring_thread" implemented by + * + * @retval 0 Normal end + * @retval <0 error (refer the errno) + * + * @param [in] arg pointer to the TUNER_DATA_TSIF structure + ******************************************************************************/ +static int tuner_drv_tsif_th(void *arg) +{ + int ret = 0; + int retval = 0; + struct sched_param param; + mm_segment_t oldfs; + int dataready = 0; + int fifo_err = 0; + int maxwaitcnt = 8; + int waitcnt; + + pr_debug("%s\n", __func__); + + /* set the priority of thread */ + param.sched_priority = TUNER_CONFIG_TSBTH_PRI; + /* daemonize("mmtuner_tsifth"); */ + + oldfs = get_fs(); + set_fs(KERNEL_DS); + ret = sched_setscheduler(g_tscnt.tsifth_id, SCHED_FIFO, ¶m); + set_fs(oldfs); + + waitcnt = maxwaitcnt; + + /* thread main loop */ + while (1) { + wait_event_interruptible(g_tscnt.tsifth_waitq, + g_tscnt.tsifth_flag); + + /* TS buffering */ + if (g_tscnt.tsifth_flag & TUNER_TSIFTH_ACTIVE) { + ret = tuner_drv_hw_tsif_get_dready(); + if (ret < 0) { + pr_debug("get DATAREADY, failed.\n"); + retval = ret; + goto out; + } else { + dataready = (uint8_t)ret; + } + if (dataready & 0x06) { /* OVER/UNDER-Run */ + if (fifo_err++ >= TUNER_TSIFTH_FIFOERROR_MAX) { + pr_err("FIFO is in serious status!!!\n"); + pr_warn("TS I/F thread go to waiting.\n"); + + g_tscnt.tsifth_flag = TUNER_TSIFTH_NONE; + g_tscnt.tsifth_wait = true; + fifo_err = 0; + continue; + } + pr_warn("OVER/UNER-Run(0x%02x) (%d).\n", + dataready, fifo_err); + dataready = 0x00; + ret = tuner_drv_hw_tsif_sync_pkt(); + if (ret) { + pr_err("tuner_drv_hw_tsif_sync_pkt() failed.\n"); + retval = ret; + goto out; + } + waitcnt = maxwaitcnt; + } + if (!(dataready & 0x01)) { /* not DATAREADY */ + + if (g_tscnt.bw == TUNER_DRV_BW1) + msleep(D_TUNER_WAIT_1SEG_MS); + else + usleep_range(500, 1000); + + if (waitcnt > 0) + waitcnt--; + continue; + } + waitcnt = maxwaitcnt; + + /* TS buffering */ + fifo_err = 0; + ret = tuner_drv_hw_tsif_get_pkts(&g_tscnt); + if (ret < 0) { + pr_err("Receive/Store TS data, failed\n"); + retval = ret; + goto out; + } + + /* TS packet buffer over-flow detection */ + if (g_tscnt.pwr <= g_tscnt.prd && + g_tscnt.prd < + g_tscnt.pwr + g_tscnt.ts_rx_size) { + if (g_tscnt.tsread_flag) + g_tscnt.ovf++; + if ((g_tscnt.ovf % 100) == 1) { + pr_info("packet buffer over flow (%d)", + g_tscnt.ovf); + } + } + + /* wake up the TS read */ + if (g_tscnt.tsread_flag == TUNER_TSREAD_WAIT) { + g_tscnt.tsread_flag = TUNER_TSREAD_IDLE; + /* wake up the TS read */ + if (waitqueue_active(&g_tscnt.tsread_waitq)) + wake_up_interruptible( + &g_tscnt.tsread_waitq); + } + } + + /* check the stop request to the TS I/F thread */ + if (g_tscnt.tsifth_flag & TUNER_TSIFTH_END) { + pr_debug("Caught the stop request.\n"); + g_tscnt.tsifth_flag = TUNER_TSIFTH_NONE; + break; + } + } /* while */ + pr_debug("Tail of thread function %s.\n", __func__); + +out: + return retval; +} + +/**************************************************************************//** + * Set TS I/F context + * + * This function detect active OFDM circuit, and calculate suitable + * memory size for handling TS data. + * After execution, the following member variables of "_tsif_context" + * structure are update. + * bw: active OFDM circuit + * ts_packet_size: byte num of an TS packet + * ts_record_size: RX transfer size a transaction. + * ts_pktbuf_size: buffer size stored by TS I/F thread + * + * @retval 0 Normal end + * @retval <0 error + * + * @param [out] ptscnt pointer to TS I/F context structure + ******************************************************************************/ +static int tuner_drv_tsif_set_cntxt(struct _tsif_cntxt *tc) +{ + int ret = 0; + uint8_t pbuf_max_size; + uint16_t pktbuf_size; + uint32_t lowerlimit; + uint32_t maxbank = 48; + uint32_t rxsize; + +#if TUNER_TSPKTBUF_MODE == 2 + const uint16_t bufsize_tbl[8] = { + 1915, 1851, 1787, 1659, 1403, 891, 635, 379}; +#else + const uint16_t bufsize_tbl[8] = { + 695, 631, 567, 439, 183, 695, 695, 695}; +#endif + +#ifdef DEBUG + const char *bwseg[3] = { "BW13", "BW1", "BW3" }; +#endif + + if (tc == NULL || tc->tsif == NULL) { + pr_err("illegal argument.\n"); + return -EINVAL; + } + if (!tc->tsifth_wait) { + pr_warn("TS buffering have been already started.\n"); + return -EINPROGRESS; + } + + /* detect the reception segment system */ + ret = tuner_drv_bwseg(&tc->bw); + if (ret) { + pr_err("tuner_drv_bwseg(), failed.\n"); + return ret; + } + +#ifdef DEBUG + pr_debug("Reception segment system: %s", bwseg[tc->bw]); +#endif + + /* TS record size a RX transaction */ + /* Readable packet number, when DATAREADY is high. */ + + /* Check packet buffer size configuration. */ + ret = tuner_drv_hw_read_reg(2, 0x62, 1, &pbuf_max_size); + if (ret) { + pr_err("Main2 register read failed.\n"); + return ret; + } + + pktbuf_size = bufsize_tbl[(pbuf_max_size>>4)&0x7]; + + /* Calculate hardware lower limit value */ + switch ((tc->tsif->thl[tc->bw]&0x7)) { + case 0: + case 6: + case 7: + lowerlimit = 16; + break; + default: + lowerlimit = (pktbuf_size)>>(6-(tc->tsif->thl[tc->bw]&0x7)); + break; + } + + rxsize = lowerlimit; + /* re-calculate lowerlimit when use fixed rxsize */ + if (tc->tsif->thl[tc->bw] >= 0x10) { + rxsize = 4<<(tc->tsif->thl[tc->bw]>>4); + if (rxsize > lowerlimit) + rxsize = lowerlimit; + } + + tc->ts_rxpkt_num = rxsize&0x07fc; + + tc->ts_rx_size = + tc->ts_rxpkt_num * g_ts_pkt_size[tc->tsif->ts_pkt_type]; + + /* TS buffer size for the TS I/F thread */ + maxbank = TUNER_MAX_TSPKTBUF_SIZE/tc->ts_rx_size; + if (maxbank > TUNER_MAX_TSPKTBUF_BANK) + maxbank = TUNER_MAX_TSPKTBUF_BANK; + + tc->ts_pktbuf_size = (tc->ts_rx_size) * maxbank; + +#ifdef DEBUG + { + uint32_t datawindow; + + if (tc->tsif->dwind[tc->bw] == 0) { + datawindow = 16; + } else { + datawindow = 0; + if (tc->tsif->dwind[tc->bw] & 0x01) + datawindow += (pktbuf_size>>5); + if (tc->tsif->dwind[tc->bw] & 0x02) + datawindow += (pktbuf_size>>4); + if (tc->tsif->dwind[tc->bw] & 0x04) + datawindow += (pktbuf_size>>3); + if (tc->tsif->dwind[tc->bw] & 0x08) + datawindow += (pktbuf_size>>2); + if (tc->tsif->dwind[tc->bw] & 0x10) + datawindow += (pktbuf_size>>1); + } + pr_info("MEMSIZE=0x%02x(%d) THL=%02x/DWIND=%02x WL(%d-%d) RXPKT=%zu BANK=%d BUFSIZE=%zu\n", + pbuf_max_size, pktbuf_size, + tc->tsif->thl[tc->bw], tc->tsif->dwind[tc->bw], + lowerlimit, lowerlimit+datawindow, + tc->ts_rxpkt_num, maxbank, tc->ts_pktbuf_size); + + } +#endif + + if ((tc->bw == 0 && tc->ts_rx_size < + (64*g_ts_pkt_size[tc->tsif->ts_pkt_type])) || + (tc->bw == 2 && tc->ts_rx_size < + (32*g_ts_pkt_size[tc->tsif->ts_pkt_type]))) { + pr_warn("Looks waterline of interrput is too low. Please confirm it.\n"); + } + + return 0; +} + +/**************************************************************************//** + * Start to receive TS data. + * + * This function activate to receive TS data. + * The "tsifth" which is the kernel thread to receive and store + * the TS data from the tuner device had been dispatched and wait. + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +static int tuner_drv_tsif_start(void) +{ + int ret = 0; + int buffer_size; + + pr_debug("%s\n", __func__); + + + if (!g_tscnt.tsifth_wait) { + /* TS I/F active! */ + pr_warn("TS buffering had already been started.\n"); + return -EINPROGRESS; + } + + ret = tuner_drv_tsif_set_cntxt(&g_tscnt); + + if (ret) { + pr_err("tuner_drv_hw_tsif_set_cntxt() failed.\n"); + return ret; + } + + pr_debug("PKTSIZE:%zu PKTNUM:%zu RXSIZE:%zu BUFSIZE:%zu\n", + g_ts_pkt_size[g_tscnt.tsif->ts_pkt_type], + g_tscnt.ts_rxpkt_num, g_tscnt.ts_rx_size, + g_tscnt.ts_pktbuf_size); + + vfree(g_tscnt.pktbuf); + kfree(g_tscnt.spibuf); + g_tscnt.pktbuf = NULL; + g_tscnt.spibuf = NULL; + +#ifdef TUNER_CONFIG_SPI_ALIGN + buffer_size = g_tscnt.ts_pktbuf_size + TUNER_CONFIG_SPI_ALIGN - 1; +#else + buffer_size = g_tscnt.ts_pktbuf_size; +#endif + +#if defined(DPATH_GPIF) && defined(TUNER_CONFIG_GPIF_DMA) + g_tscnt.pktbuf = kmalloc(buffer_size, GFP_KERNEL | GFP_DMA); +#else + g_tscnt.pktbuf = vmalloc_user(buffer_size); +#endif + + if (g_tscnt.pktbuf == NULL) { + pr_err("memory allocation failed.\n"); + return -ENOMEM; + } + + g_tscnt.spibuf = kmalloc(g_tscnt.ts_rx_size, GFP_KERNEL); + if (g_tscnt.spibuf == NULL) { + vfree(g_tscnt.pktbuf); + pr_err("memory allocation failed.(spibuf)\n"); + return -ENOMEM; + } + memset(g_tscnt.pktbuf, 0, g_tscnt.ts_pktbuf_size); + memset(g_tscnt.spibuf, 0, g_tscnt.ts_rx_size); + g_tscnt.pwr = g_tscnt.prd = 0; + g_tscnt.ovf = 0; + + ret = tuner_drv_hw_tsif_config(&g_tscnt); + if (ret) { + pr_err("tuner_drv_hw_tsif_config() failed.\n"); + vfree(g_tscnt.pktbuf); + kfree(g_tscnt.spibuf); + return ret; + } + + /* TS read operation is IDLE state. */ + g_tscnt.tsread_flag = TUNER_TSREAD_IDLE; + pr_debug("TS-Read Timeout limit: %lu [ms]\n", + TUNER_CONFIG_TSREAD_TIMEOUT); + + ret = tuner_drv_hw_tsif_sync_pkt(); + if (ret) { + pr_err("tuner_drv_hw_tsif_sync_pkt failed.\n"); + vfree(g_tscnt.pktbuf); + kfree(g_tscnt.spibuf); + return ret; + } + + g_tscnt.tsifth_flag = TUNER_TSIFTH_ACTIVE; + /* re-activate TS I/F */ + if (waitqueue_active(&g_tscnt.tsifth_waitq)) + wake_up_interruptible(&g_tscnt.tsifth_waitq); + g_tscnt.tsifth_wait = false; + + + return ret; +} + +/**************************************************************************//** + * Stop receiving TS data. + * + * This function make the TS I/F thread wait status. + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +static int tuner_drv_tsif_stop(void) +{ + int ret = 0; + uint32_t i = 0; + + pr_debug("%s\n", __func__); + + if (g_tscnt.tsifth_wait) { + /* TS I/F is NOT active! */ + pr_warn("TS buffering is not active.\n"); + return 0; + } + + /* stop (be waiting status) TS I/F thread */ + g_tscnt.tsifth_flag = TUNER_TSIFTH_NONE; + g_tscnt.tsifth_wait = true; + + /* confirm the status of the TS I/F thread */ + while (1) { + /* + * NOTE + * It takes about 20-30[ms] to become able to detect the TS + * I/F thread changed in waiting state in the return value of + * the waitqueue_activate() function. + */ + if (waitqueue_active(&g_tscnt.tsifth_waitq)) { + pr_debug("TS I/F thread is going to do the stop procedure.\n"); + break; + } + + usleep_range(TUNER_TSIFTH_SLEEP_MIN, TUNER_TSIFTH_SLEEP_MAX); + + i++; + if (i >= TUNER_TSIFTH_SLEEP_RETRY) { + pr_crit("cannot stop TS I/F thread.\n"); + break; + } + } + + /* release the waiting in TS read operation */ + if (g_tscnt.tsread_flag == TUNER_TSREAD_WAIT) { + g_tscnt.tsread_flag = TUNER_TSREAD_END; + /* release the waiting in TS read operation */ + if (waitqueue_active(&g_tscnt.tsread_waitq)) + wake_up_interruptible(&g_tscnt.tsread_waitq); + } + + g_tscnt.pwr = g_tscnt.prd = 0; + g_tscnt.ovf = 0; + g_tscnt.ts_rxpkt_num = 0; + g_tscnt.ts_rx_size = 0; + g_tscnt.ts_pktbuf_size = 0; + + vfree(g_tscnt.pktbuf); + kfree(g_tscnt.spibuf); + kfree(g_tscnt.tsif); + + g_tscnt.pktbuf = NULL; + g_tscnt.spibuf = NULL; + g_tscnt.tsif = NULL; + + return ret; +} + +/**************************************************************************//** + * return TS packet size + * + * @retval >0 packet size + * @retval <0 error + ******************************************************************************/ +static int tuner_drv_tsif_pktsize(void) +{ + if (g_tscnt.tsifth_wait) { + pr_warn("TS buffering is not started.\n"); + return -EAGAIN; + } + + return (int)(g_ts_pkt_size[g_tscnt.tsif->ts_pkt_type]); +} + +/**************************************************************************//** + * @brief Call-back function for TS-Read Timeout. + * + ******************************************************************************/ +static void tsread_timer_handler(unsigned long data) +{ + pr_info("Timeout (registered %ld, now %ld).", data, jiffies); + + if (g_tscnt.tsread_flag != TUNER_TSREAD_WAIT) { + pr_info("Timer is not to be restarted."); + return; + } + + g_tscnt.tsread_flag = TUNER_TSREAD_TIMEOUT; + /* time out wake up*/ + if (waitqueue_active(&g_tscnt.tsread_waitq)) + wake_up_interruptible(&g_tscnt.tsread_waitq); +} + +/**************************************************************************//** + * return TS block count + * + * @retval >0 block size + * @retval <0 error + ******************************************************************************/ +static int tuner_drv_tsif_blksize(void) +{ + if (g_tscnt.tsifth_wait) { + pr_warn("TS buffering is not started.\n"); + return -EAGAIN; + } + + return (int)(g_tscnt.ts_rxpkt_num); +} + + +/**************************************************************************//** + * detect active OFDM block (BW13 or BW01) + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +static inline int tuner_drv_bwseg(enum _bw_seg *pbw) +{ + int ret; + uint8_t rd; + uint8_t sys; + + ret = tuner_drv_hw_read_reg(Main1, 0x02, 1, &rd); /* SYSSET */ + if (ret) { + pr_debug("register SYSSET, read fail.\n"); + return ret; + } + sys = (rd & 0xC0) >> 6; /* SYS is SYSSET[7:6]. */ + switch (sys) { + case 0: + *pbw = TUNER_DRV_BW13; + break; + case 1: + *pbw = TUNER_DRV_BW1; + break; + case 3: + *pbw = TUNER_DRV_BW3; + break; + default: + pr_err("illegal SYS parameter.\n"); + return -EFAULT; + } + + return 0; +} + +#endif /* TUNER_CONFIG_DPATH != TUNER_DPATH_NONE */ + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Socionext Inc."); +MODULE_DESCRIPTION("MM Tuner Driver"); + +module_init(tuner_drv_start); +module_exit(tuner_drv_end); +/******************************************************************************* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************/ diff --git a/drivers/misc/mm_tuner/src/tuner_drv_hw.c b/drivers/misc/mm_tuner/src/tuner_drv_hw.c new file mode 100644 index 0000000000000000000000000000000000000000..399d8dd7534e7fb49835dae8cc4dc1273d19c3df --- /dev/null +++ b/drivers/misc/mm_tuner/src/tuner_drv_hw.c @@ -0,0 +1,318 @@ +/**************************************************************************//** + * + * @file tuner_drv_hw.c + * + * @brief The HW Wrapping Layer for Tmm Tuner Driver + * + ***************************************************************************//* + * Copyright (c) 2015 Socionext Inc. + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + ******************************************************************************/ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +/*..+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...*/ +/****************************************************************************** + * include + ******************************************************************************/ +#include "tuner_drv.h" +#include "tuner_drv_hw.h" + +#ifdef TUNER_CONFIG_IRQ_ENABLE +#include +#include +#include +#endif + +/****************************************************************************** + * data + ******************************************************************************/ +static bool g_tuner_irq_flag; + +#if defined(DPATH_SPI) || defined(DPATH_SDIO) || defined(DPATH_GPIF) + /* Configuration registers list for slave i/f. */ + /* Don't Edit from here */ +struct snglreg slvif_cfgregs[] = { + { Main2, 0x6B, 0x20, 0x20 }, /* #0 EXINTSET.SLVINTEN = 1 */ + { Main1, 0xE2, 0xF0, 0x90 }, /* #1 INTSET5.ISEGSEL[3:0] = 9 */ + /* #2 STM_SYNCSEL[4:0] DOSET4[4:0] = 1 */ + { Main1, 0xD9, 0x1F, 0x01 }, + /* #3 PKTWLSET1.DATA_WINDOW0[4:0], PKTWLSET2.LOWER_LEVEL0[2:0] */ + { Main2, 0x66, 0xFF, 0x00 }, + /* #4 PKTBUFCTL.ECONFIG[1:0] Set byte order of slave i/f */ + { Main2, 0x60, 0x40, 0x00 }, + /* #5 PKTSYNCC3[7:4] COFF2=ON NULLOFF2=ON */ + { Main2, 0x65, 0x90, 0x90 }, + /* #6 IFPWDSET1[6].[2:1] PKTBUF0,INTGEN0,PKTPACK0 ON*/ + { Main2, 0x70, 0x46, 0x00 }, +#ifdef TUNER_CONFIG_PF_NULLFILTER + { Main2, 0x70, 0x01, 0x00 }, /* #7 IFPWDSET1[0] PF0 CLK ON */ + /* #8 PFTBLSET0A ADDR=0x41(PF0CONFIG) Set address */ + { Main2, 0x59, 0xFF, 0x41 }, + /* #9 PFTBLSET0L DATA_LOW=0x02 Set Null Filter Enable */ + { Main2, 0x57, 0x02, 0x02 }, + /* #10 PFTBLSET0U DATA_HI=0x00 */ + { Main2, 0x58, 0xFF, 0x00 }, + /* #11 PFTBLSET0A ADDR=0x41(PF0CONFIG) Write Data */ + { Main2, 0x59, 0xFF, 0xC1 }, +#endif + /* Don't Edit to here */ + + /* If you want to add any setting the below */ + /* { Mainx , 0xxx, 0xxx, 0x00 }, */ + + /* End Mark. Do not remove this line */ + { END_SLVCFG, 0x00, 0x00, 0x00 } + +}; +#endif + + +/****************************************************************************** + * code area + ******************************************************************************/ + +/**************************************************************************//** + * interruption registration control of a driver + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +int tuner_drv_hw_reqirq(void) +{ + int ret = 0; /* function return */ + + /* the sub-system of IRQ has been already activated */ + if (g_tuner_irq_flag == true) { + pr_debug("IRQ (#%d) is already active, so do nothing\n", + TUNER_CONFIG_INT); + return 0; + } + +#ifdef TUNER_CONFIG_IRQ_ENABLE + pr_debug("*** request IRQ ***\n"); + /* request IRQ */ + ret = request_irq( + TUNER_CONFIG_INT, /* number of IRQ */ + tuner_interrupt, /* call-back function */ + IRQF_TRIGGER_RISING, + "mm_tuner", /* IRQ name */ + NULL /* device ID is not specified */ + ); + if (ret != 0) { + pr_err("request_irq() fail (return:%d)\n", ret); + return -EINVAL; + } +#else +#ifdef DEBUG + pr_debug("TUNER_CONFIG_IRQ_ENABLE is not defined\n"); +#endif +#endif + /* IRQ status flag: on */ + g_tuner_irq_flag = true; + + return ret; +} + +/**************************************************************************//** + * interruption registration release control of a driver + * + ******************************************************************************/ +void tuner_drv_hw_freeirq(void) +{ + if (g_tuner_irq_flag == false) { + /* IRQ line is not active */ + pr_debug("IRQ (#%d) is not active, so do nothing.\n", + TUNER_CONFIG_INT); + return; + } + +#ifdef TUNER_CONFIG_IRQ_ENABLE + /* disable IRQ line */ + pr_debug("*** FREE IRQ ***\n"); + free_irq(TUNER_CONFIG_INT, NULL); +#else +#ifdef DEBUG + pr_debug("TUNER_CONFIG_IRQ_ENABLE is not defined.\n"); +#endif +#endif + + /* flag off */ + g_tuner_irq_flag = false; +} + +/**************************************************************************//** + * Write masked bits of the Register. (Read and Modified Write) + * + * @retval 0 Normal end + * @retval <0 error (refer the errno) + * + * @param [in] bank register bank enumerator + * @param [in] adr start address for continuous write + * @param [in] mask continuous write length + * @param [in] wd write data + ******************************************************************************/ +int tuner_drv_hw_rmw_reg(enum _reg_bank bank, uint8_t adr, + uint8_t mask, uint8_t wd) +{ + int ret; + uint8_t data; + + if (mask == 0x00) { + pr_warn("%s(): Bitmask is 0x00, so write nothing.\n", __func__); + goto _out; + } + if (mask == 0xff) { + data = wd; + } else { + ret = tuner_drv_hw_read_reg(bank, adr, 1, &data); + if (ret) + return ret; + data = (data & ~mask) | wd; + pr_debug("%s(): R,M(m:0x%02x,d:0x%02x),W(0x%02x).\n", __func__, + mask, wd, data); + } + ret = tuner_drv_hw_write_reg(bank, adr, 1, &data); + if (ret) + return ret; + +_out: + return 0; +} + +/**************************************************************************//** + * @brief Set the event (interrupt) condition. + * + * This function set some specified interrupt (event) conditions, + * and, be enable the interrupt sub system. + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +int tuner_drv_hw_setev(union _tuner_data_event *ev) +{ + int ret; + uint8_t buf[2] = { 0x00, 0x00 }; + + pr_debug("mode:%u intset1:0x%02x intdef1:0x%02x intdef2:0x%01x", + ev->set.mode, ev->set.intset1, ev->set.intdef1, ev->set.intdef2); + + if (ev->set.mode == TUNER_EVENT_MODE_ADD) { + /* read INTDEF1 and INTDEF2 */ + ret = tuner_drv_hw_read_reg(Main1, 0xDC, 2, buf); + if (ret) { + pr_err("Read INTDEF1/2, failed\n"); + return ret; + } + buf[0] |= ev->set.intdef1; + buf[1] |= ev->set.intdef2; + } else { /* Overwrite mode: TUNER_EVENT_MODE_OVW */ + buf[0] = ev->set.intdef1; + buf[1] = ev->set.intdef2; + } + + /* write INTDEF1 and INTDEF2 */ + ret = tuner_drv_hw_write_reg(Main1, 0xDC, 2, buf); + if (ret) { + pr_err("Write INTDEF1/2, fail.\n"); + return ret; + } + + /* write INTSET1[3](NINTEN) and NITSET1[0](INTMD) */ + ret = tuner_drv_hw_rmw_reg(Main1, 0xDE, 0x09, ev->set.intset1); + if (ret) { + pr_err("Write INTSET1.NINTEN/INTMD, failed\n"); + return ret; + } + if ((buf[0] | (buf[1] & 0x0F)) != 0x00) { + pr_debug("Enable system IRQ line.\n"); + ret = tuner_drv_hw_reqirq(); + if (ret) { + pr_err("tuner_drv_hw_reqirq() failed.\n"); + return ret; + } + } + + return 0; /* normal exit */ +} + +/**************************************************************************//** + * Clear the IRQ (interrupt) conditions. + * + * This function clear the specified interrupt conditions. + * And, be disabled the IRQ sub-system, when the all interrupt conditions + * are not active. + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +int tuner_drv_hw_relev(union _tuner_data_event *ev) +{ + int ret; + uint8_t buf[2] = { 0x00, 0x00 }; + + /* read INTDEF1/2 */ + ret = tuner_drv_hw_read_reg(Main1, 0xDC, 2, buf); + if (ret) { + pr_err("Read INTDEF1/2, failed.\n"); + return ret; + } + + /* clear specified bits */ + buf[0] &= ~(ev->set.intdef1); + buf[1] &= ~(ev->set.intdef2); + + /* write INTDEF1/2 */ + ret = tuner_drv_hw_write_reg(Main1, 0xDC, 2, buf); + if (ret) { + pr_debug("Write INTDEF1/2, failed.\n"); + return ret; + } + + if ((buf[0] | (buf[1] & 0x0F)) == 0x00) { + pr_debug("Disable system IRQ line.\n"); + tuner_drv_hw_freeirq(); + } + + return 0; /* normal return */ +} + +#ifdef TUNER_CONFIG_IRQ_LEVELTRIGGER +/**************************************************************************//** + * interruption registration enable control of a driver + * + ******************************************************************************/ +void tuner_drv_hw_enable_interrupt(void) +{ + /* enabling interrupt */ + enable_irq(TUNER_CONFIG_INT, NULL); +} + +/**************************************************************************//** + * interruption registration disable control of a driver + * + ******************************************************************************/ +void tuner_drv_hw_disable_interrupt(void) +{ + /* disabling interrupt */ + disable_irq(TUNER_CONFIG_INT, NULL); +} +#endif /* TUNER_CONFIG_IRQ_LEVELTRIGGER */ +/******************************************************************************* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************/ diff --git a/drivers/misc/mm_tuner/src/tuner_drv_hw_spi.c b/drivers/misc/mm_tuner/src/tuner_drv_hw_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..b50d9de524d55d476cc50c3fd7ba463b90001aa0 --- /dev/null +++ b/drivers/misc/mm_tuner/src/tuner_drv_hw_spi.c @@ -0,0 +1,1219 @@ +/**************************************************************************//** + * + * @file tuner_drv_hw_spi.c + * + * @brief Implementation of the hardware control layer in SPI. + * + ****************************************************************************//* + * Copyright (c) 2015 Socionext Inc. + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + ******************************************************************************/ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +/*..+....1....+....2....+....3....+....4....+....5....+....6....+....7....+...*/ +/****************************************************************************** + * include + ******************************************************************************/ +#include "tuner_drv_hw.h" + +#if defined(SPI_GP_MESURE_DEBUG) || defined(DSPI_DR_MESURE_DEBUG) +#include +#endif + +#include +#include + +#ifdef TUNER_CONFIG_SPI_DIVMSG +#include +#endif + +/****************************************************************************** + * function + ******************************************************************************/ +static int tuner_drv_spi_probe(struct spi_device *spidev); +static int tuner_drv_spi_remove(struct spi_device *spidev); + +/* Private functions */ +#ifdef TUNER_CONFIG_SPI_EDGE +static int tuner_drv_spi_edge(int ctrl); +static int tuner_drv_spi_calibration(void); +#endif + + +#if defined(TUNER_CONFIG_SPI_EXTREAD) || defined(TUNER_CONFIG_AES_ENABLE) +static int tuner_drv_hw_tsif_set_dmycnt(unsigned int cnt); +#endif + +#define SPI_CMD_NUM 0xc +#define SPI_DATA_NUM 0xc +#define SPI_PRG_MAX_NUM 0x100 +#define SPI_PSEQ_ADRS_INIT 0x00 +#define SPI_BREAKCODE_PATTERN {0xff, 0xfe, 0x81, 0x00} + +/****************************************************************************** + * Macro + ******************************************************************************/ +#define CALC_LENGTH(len) ((len >= SPI_PRG_MAX_NUM) ? SPI_PRG_MAX_NUM : len) + +#define SPI_TSREAD_DMYCNT 10 + +/* SPI configuration setting(SPI internal register address=0x08) for each mode +* SPI_DIVMSG SPI_BREAKCODE SPI_CONFIG_SET +* ON OFF 0x00 : XCS_RESET=OFF , TRANSFER BREAK=DISABLE +* ON ON 0x02 : XCS_RESET=OFF , TRANSFER BREAK=ENABLE +* OFF OFF 0x03(0x01) : XCS_RESET=ON , TRANSFER BREAK=DISABLE +* OFF ON 0x03 : XCS_RESET=ON , TRANSFER BREAK=ENABLE +*/ + +#if defined(TUNER_CONFIG_SPI_DIVMSG) && defined(TUNER_CONFIG_SPI_BREAKCODE) +#define SPI_CONFIG_SET (0x02) +#define CMDBUF_POS(x) (void *)(x) +#define CMDBUF_LEN(x) (x+4) +#elif defined(TUNER_CONFIG_SPI_DIVMSG) && !defined(TUNER_CONFIG_SPI_BREAKCODE) +#define SPI_CONFIG_SET (0x00) +#define CMDBUF_POS(x) (void *)(x+4) +#define CMDBUF_LEN(x) (x) +#elif !defined(TUNER_CONFIG_SPI_DIVMSG) && !defined(TUNER_CONFIG_SPI_BREAKCODE) +#define SPI_CONFIG_SET (0x03) +#define CMDBUF_POS(x) (void *)(x+4) +#define CMDBUF_LEN(x) (x) +#else + /* elif !defined(TUNER_CONFIG_SPI_DIVMSG) && +* defined(TUNER_CONFIG_SPI_BREAKCODE) + */ +#define SPI_CONFIG_SET (0x03) +#define CMDBUF_POS(x) (void *)(x) +#define CMDBUF_LEN(x) (x+4) +#endif + +#if defined(TUNER_CONFIG_SPI_EXTREAD) || defined(TUNER_CONFIG_AES_ENABLE) +/* Extend Read command for AES */ +#define SPI_READ_COMMAND 0x3b +#else +/* Normal Read command */ +#define SPI_READ_COMMAND 0x0b +#endif + + +#if defined(TUNER_CONFIG_SPI_ALIGN) +#define BUFLEN_ALIGN(size) ((size + (TUNER_CONFIG_SPI_ALIGN - 1))&\ + (~(TUNER_CONFIG_SPI_ALIGN - 1))) +/* For example +* TUNER_CONFIG_SPI_ALIGN = 1024 +* Expression : (size + 1023) & 0xffffffc00 +* size : 256*188=48128 : +* (48128+1023)&0xfffffc00 = 0xbc00 = 48128 = 256*188 ( Aligned ) +* size : 344*188=64672 : +* (64672+1023)&0xfffffc00 = 0x10000 = 65536 = 344*188 + 864 +*/ + +#ifndef TUNER_CONFIG_SPI_DIVMSG +#error "TUNER_CONFIG_SPI_ALIGN requires TUNRE_CONFIG_SPI_DIVMSG" +#endif + +#else +#define BUFLEN_ALIGN(size) (size) +#endif + +#define D_TUNER_SPI_MATCH_TABLE "socionext,mn553-spi" + +/****************************************************************************** + * global + ******************************************************************************/ +#ifdef TUNER_CONFIG_SPI_DIVMSG +DEFINE_MUTEX(g_spi_mutex); +#define mtxLock() mutex_lock(&g_spi_mutex) +#define mtxUnlock() mutex_unlock(&g_spi_mutex) +#else +#define mtxLock() +#define mtxUnlock() +#endif + +/****************************************************************************** + * data + ******************************************************************************/ +static const struct of_device_id spi_dt_match[] = { + { + .compatible = D_TUNER_SPI_MATCH_TABLE + }, + { }, +}; +MODULE_DEVICE_TABLE(of, spi_dt_match); + +static struct spi_driver mn8855x_spi_driver = { + .driver = { + .name = "553spi", + .owner = THIS_MODULE, + .of_match_table = spi_dt_match, + }, + .probe = tuner_drv_spi_probe, + .remove = tuner_drv_spi_remove, +}; + +struct spi_drvdata { + struct spi_device *spi; + spinlock_t spi_lock; +}; + +static struct spi_drvdata *g_spi_drvdata; + +/****************************************************************************** + * Variable + ******************************************************************************/ +#ifdef TUNER_CONFIG_SPI_EDGE +static int g_edge_mode; +#endif +/****************************************************************************** + * code area + ******************************************************************************/ +/**************************************************************************//** + * Set TPM register + * + * The TPM (register of the tuner device) control the I/F port of + * the tuner device. + * TPM must be set to 0x02 when the Data-PATH (TS I/F) use SPI and + * Control-PATH use I2C. + * + * @retval 0 Normal end + * @retval <0 error + ******************************************************************************/ +int tuner_drv_hw_tsif_set_tpm(void) +{ + int ret = 0; + uint8_t buf = 0x00; + + /* TPM[4:0] (PINCNT0[4:0]) */ + ret = tuner_drv_hw_read_reg(Main2, 0x00, 1, &buf); + if (ret) { + pr_err("Read PINCNT0, failed.\n"); + return ret; + } + if ((buf & 0x1F) != 0x0a) { /* NOT Diver Mode */ +#ifdef CPATH_I2C + buf = 0x02; /* CPATH:I2C, DPATH:SPI(slave-IF) */ +#else + buf = 0x00; /* CPATH:SPI, DPATH:SPI(slave-IF) */ +#endif + ret = tuner_drv_hw_write_reg(Main2, 0x00, 1, &buf); + if (ret) { + pr_err("write PINCNT0.TPM, failed.\n"); + return ret; + } + } + return ret; +} + +/**************************************************************************//** + * address incremental read from some registers of the Tuner device. + * + * @retval 0 Normal end + * @retval <0 error + * + * @param [in] bank register bank enumerator + * @param [in] adr address of the register to read-out start + * @param [in] len continuous read length + * @param [out] rd pointer to the buffer + ******************************************************************************/ +#ifdef CPATH_SPI +int tuner_drv_hw_read_reg(enum _reg_bank bank, uint8_t adr, uint16_t len, + uint8_t *rd) +{ + int ret = 0; + struct spi_message msg; + struct spi_transfer xfer; + + unsigned short loop_cnt; + unsigned char read_data; + + /* breakcode 0xff, 0xfe, 0x81, 0x00 */ + uint8_t scmd[SPI_CMD_NUM] = { 0xff, 0xfe, 0x81, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t sdata[SPI_DATA_NUM]; + uint8_t bank_set[3] = { + 0x90, /* Sub 0x80(I2C) + 0x10(R) + 0x00 */ + 0x91, /* Main1 0x80(I2C) + 0x10(R) + 0x01 */ + 0x92 /* Main2 0x80(I2C) + 0x10(R) + 0x02 */ + }; + uint8_t n = 0; + + if (g_spi_drvdata == NULL) { + pr_debug("[%s](%d) ERR:can't spi read. g_spi_drvdata NULL", + __func__, __LINE__); + return -EINVAL; + } + + if (bank > Main2) { + pr_err("[%s](%d) Illegal bank %d\n", __func__, __LINE__, bank); + return -EINVAL; + } + + /* access loop */ + for (loop_cnt = 0; loop_cnt < len; loop_cnt++) { + memset(sdata, 0x00, sizeof(unsigned char) * SPI_DATA_NUM); + memset(&xfer, 0, sizeof(struct spi_transfer)); + + spi_message_init(&msg); + + scmd[4 + 0] = 0x03; /* command(read) */ + scmd[4 + 1] = bank_set[bank]; /* bank */ + scmd[4 + 2] = (uint8_t) (adr + n); /* address */ + + xfer.tx_buf = CMDBUF_POS(scmd); + xfer.len = CMDBUF_LEN(8); + xfer.bits_per_word = 8; + xfer.rx_buf = CMDBUF_POS(sdata); + + spi_message_add_tail(&xfer, &msg); + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + mtxUnlock(); + if (ret) { + pr_debug("spi_sync() return with %d", ret); + return ret; + } + + /* read data */ + /* MOSI = {0x72, xx, xx, xx, RD, RD, RD, RD} */ + read_data = sdata[11]; + *(rd + n) = read_data; + + n++; + } +#ifdef DEBUG + { + int i; + char lbuf[128] = { 0 }; + + pr_debug("SPI(R) bank:%d bankset:0x%02x offset:0x%02x len:%d\n", + (int)bank, bank_set[(int)bank], adr, len); + for (i = 0; i < len; i++) { + if (0 == (i % 16)) { + if (i) + pr_debug("%s\n", lbuf); + snprintf(lbuf, sizeof(lbuf)-1, "[%04x] %02x", + i, rd[i]); + } else { + snprintf(lbuf, sizeof(lbuf)-1, "%s %02x", + lbuf, rd[i]); + } + } + pr_debug("%s\n", lbuf); + } +#endif + + return ret; +} + +/**************************************************************************//** + * address incremental write to some registers of the Tuner device. + * + * @retval 0 Normal end + * @retval <0 error (refer the errno) + * + * @param [in] bank register bank enumerator + * @param [in] adr start address for continuous write + * @param [in] len continuous write length + * @param [out] wd pointer to the write data array + ******************************************************************************/ +int tuner_drv_hw_write_reg(enum _reg_bank bank, uint8_t adr, uint16_t len, + uint8_t *wd) +{ + int ret = 0; + struct spi_message msg; + struct spi_transfer xfer; + + unsigned short loop_cnt; + unsigned char write_data; + + /* breakcode 0xff, 0xfe, 0x81, 0x00 */ + uint8_t scmd[SPI_CMD_NUM] = { 0xff, 0xfe, 0x81, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t bank_set[3] = { + 0x80, /* Sub 0x80(I2C) + 0x00(W) + 0x00 */ + 0x81, /* Main1 0x80(I2C) + 0x00(W) + 0x01 */ + 0x82, /* Main2 0x80(I2C) + 0x00(W) + 0x02 */ + }; + int i; + uint8_t n = 0; + + if (g_spi_drvdata == NULL) { + pr_debug("[%s](%d) ERR:can't spi read. g_spi_drvdata NULL", + __func__, __LINE__); + return -EINVAL; + } + + if (bank > Main2) { + pr_err("[%s](%d) Illegal bank %d\n", __func__, __LINE__, bank); + return -EINVAL; + } + + memset(&xfer, 0, sizeof(struct spi_transfer)); + + /* access loop */ + for (loop_cnt = 0; loop_cnt < len; loop_cnt++) { + memset(&xfer, 0, sizeof(struct spi_transfer)); + + spi_message_init(&msg); + + scmd[4 + 0] = 0x03; /* command(write) */ + scmd[4 + 1] = bank_set[bank]; /* bank */ + scmd[4 + 2] = (unsigned char) adr + n; /* address */ + /* write data */ + write_data = *(wd + n); + for (i = 3; i < 8; i++) + scmd[4 + i] = write_data; + + xfer.tx_buf = CMDBUF_POS(scmd); + xfer.len = CMDBUF_LEN(8); + xfer.bits_per_word = 8; + + spi_message_add_tail(&xfer, &msg); + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + mtxUnlock(); + if (ret) { + pr_debug("spi_sync() return with %d", ret); + return ret; + } + n++; + } + +#ifdef DEBUG + { + int i; + char lbuf[128] = { 0 }; + + pr_debug("SPI(W) bank:%d bankset:0x%02x adr:0x%02x len:%d", + (int)bank, bank_set[(int)bank], adr, len); + for (i = 0; i < len; i++) { + if (0 == (i % 16)) { + if (i) + pr_debug("%s\n", lbuf); + snprintf(lbuf, sizeof(lbuf)-1, "[%04x] %02x", + i, wd[i]); + } else { + snprintf(lbuf, sizeof(lbuf)-1, "%s %02x", + lbuf, wd[i]); + } + } + pr_debug("%s\n", lbuf); + } +#endif + + return ret; +} + +/************************************************************************//** + * address incremental write for PSEQ/TNCTL program download + * to the Tuner device. + * @retval 0 Normal end + * @retval <0 error (refer the errno) + * + * @param [in] bank register bank enumerator + * @param [in] adr start address for continuous write + * @param [in] len continuous write length + * @param [out] wd pointer to the write data array + ****************************************************************************/ +int tuner_drv_hw_write_prg(enum _reg_bank bank, uint8_t adr, + uint16_t len, uint8_t *wd) +{ + int ret = 0; + struct spi_message msg; + struct spi_transfer xfer; + uint8_t buf[3]; + uint8_t scmd[SPI_PRG_MAX_NUM + 4 + 4]; + uint8_t stadu = 0x00; + uint8_t stadl = 0x00; + + int i, loop_cnt; + uint16_t write_length = 0; + int16_t remain_length = 0; + uint16_t n = 0; + + const uint8_t stadu_mask[3] = { + 0x3F, /* TNCSTAD[12:8] is TNCSTADU[4:0] */ + 0x00, /* (ignore) */ + 0x1F /* PSCSTAD[ */ + }; + const uint8_t dl_flg[3] = { + 0x01, /* Sub (TNCTL) */ + 0xFF, /* (ignore) */ + 0x00 /* Main2 (PSCTL) */ + }; + + struct snglreg rmw[3] = { + /** + * Upper bits of the offset address for up-loading firmware + */ + { bank, 0xF4, stadu_mask[bank], 0x00, }, /* *STADU */ + /** + * Lower bits of the offset address for up-loading firmware + */ + { bank, 0xF5, 0xFF, 0x00, }, /* *STADL */ + /** + * PSEQ Program Reset (*PGRST) + */ + { bank, 0xF3, 0x02, 0x02, } /* *PGRST */ + }; + + const uint8_t break_code[] = { 0xff, 0xfe, 0x81, 0x00, }; + + if (g_spi_drvdata == NULL) { + pr_debug("[%s](%d) ERR:can't spi read. g_spi_drvdata NULL", + __func__, __LINE__); + return -EINVAL; + } + + if (bank != Main2 && bank != Sub) { + pr_err("[%s](%d) Illegal bank %d\n", __func__, __LINE__, bank); + return -EINVAL; + } + + memset(&xfer, 0, sizeof(struct spi_transfer)); + + /* PRTYMD setting */ + ret = tuner_drv_hw_rmw_reg(bank, 0xF2, 0x40, 0x40); /* PRTYMD=1 */ + if (ret) { + pr_err("Write PRTYMD of bank#%d, failed.\n", bank); + return ret; + } + + memcpy(scmd, break_code, sizeof(break_code)); + + /* access loop */ + loop_cnt = 0; + remain_length = len; + do { + rmw[0].param = stadu + (loop_cnt & 0x00FF); + rmw[1].param = stadl; + + for (i = 0; i < 3; i++) { + ret = tuner_drv_hw_rmw_reg(rmw[i].bank, rmw[i].adr, + rmw[i].enabit, rmw[i].param); + if (ret) + return ret; + } + + write_length = CALC_LENGTH(remain_length); + remain_length -= write_length; + memset(scmd+8, 0x00, sizeof(unsigned char) * (write_length)); + memset(&xfer, 0, sizeof(struct spi_transfer)); + + spi_message_init(&msg); + + scmd[4 + 0] = 0x02; /* command */ + scmd[4 + 1] = dl_flg[bank]; /* 0: PSEQ / 1: TNCTL */ + /* size(upper) */ + scmd[4 + 2] = (write_length >> 8) & 0x00FF; + scmd[4 + 3] = write_length & 0x00FF; /* size(lower) */ + /* write data */ + for (i = 0; i < write_length; i++) { + scmd[4 + i + 4] = *(wd + n); + n++; + } + + xfer.tx_buf = CMDBUF_POS(scmd); + xfer.len = CMDBUF_LEN(write_length + 4); + xfer.bits_per_word = 8; + + spi_message_add_tail(&xfer, &msg); + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + mtxUnlock(); + if (ret) { + pr_debug("spi_sync() return with %d", ret); + return ret; + } + + WARN_ON(remain_length < 0); + if (remain_length == 0) + break; + + loop_cnt++; + } while (-1); + + /* Dummy read */ + ret = tuner_drv_hw_read_reg(bank, 0xF8, 1, buf); + if (ret) { + pr_err("RAM read mode setting fail.\n"); + return ret; + } + + return ret; +} +#endif /* CPATH_SPI */ + +/**************************************************************************//** + * Register the TS I/F driver + * + * @retval 0 Normal end + * @retval <0 error + ******************************************************************************/ +int tuner_drv_hw_tsif_register(void) +{ + int ret = 0; + + pr_debug("%s\n", __func__); + + ret = spi_register_driver(&mn8855x_spi_driver); + if (ret) { + pr_err("spi_register_driver() failed.\n"); + return ret; + } + + return ret; +} + +/**************************************************************************//** + * Configure the SPI-Slave I/F of the tuner device. + * + * @retval 0 Normal end + * @retval <0 error + * + * @param [in] + ******************************************************************************/ +int tuner_drv_hw_tsif_config(struct _tsif_cntxt *tc) +{ + int ret = 0; + struct _tuner_data_tsif *tsif; + union _tuner_data_event iberint; + int i; + + /* breakcode 0xff, 0xfe, 0x81, 0x00 */ + uint8_t tx[12] = { 0xff, 0xfe, 0x81, 0x00, + 0x03, 0x00, 0x08, 0x00, SPI_CONFIG_SET, 0x00, 0x00, 0x00 }; + struct spi_message msg; + struct spi_transfer xfer; + uint8_t pbuf_max_size = 0; + uint8_t byte_order_set = 0; + + pr_debug("%s\n", __func__); + + ret = tuner_drv_hw_tsif_set_tpm(); + if (ret) { + pr_err("tuner_drv_hw_tsif_set_tpm() failed.\n"); + return ret; + } + + if (tc == NULL || tc->tsif == NULL) { + pr_err("illegal arguments.\n"); + return -EINVAL; + } + + tsif = (struct _tuner_data_tsif *) tc->tsif; + + /* configure the SPI(slave) I/F sub-system of Tuner device */ + memset(&xfer, 0, sizeof(struct spi_transfer)); + spi_message_init(&msg); + + xfer.tx_buf = (void *) tx; + xfer.len = 4 + 8; + xfer.bits_per_word = 8; + spi_message_add_tail(&xfer, &msg); + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + mtxUnlock(); + if (ret) { + pr_err("spi_sync() failed. (return:%d).\n", ret); + return ret; + } + +#if defined(TUNER_CONFIG_SPI_EXTREAD) || defined(TUNER_CONFIG_AES_ENABLE) + tuner_drv_hw_tsif_set_dmycnt(SPI_TSREAD_DMYCNT); +#endif + +#ifdef TUNER_CONFIG_SPI_EDGE + tuner_drv_spi_edge(1); + ret = tuner_drv_spi_calibration(); + if (ret) { + pr_err("tuner_drv_spi_calibration() failed. (return:%d).\n", + ret); + return ret; + } +#endif + + /* Water Line setting */ + slvif_cfgregs[SLVIF_CFG_WATERLINE].param = + ((uint8_t) (tsif->dwind[tc->bw]) << 3) | (tsif->thl[tc->bw]&0x7); + + /* Byte order configuration */ + if (tsif->spi_ts_bit_per_word == 32) { +#ifdef TUNER_CONFIG_SLV_MSBFIRST + slvif_cfgregs[SLVIF_CFG_BYTEORDER].param = 0x00; +#else + slvif_cfgregs[SLVIF_CFG_BYTEORDER].param = 0x40; +#endif + } else { + slvif_cfgregs[SLVIF_CFG_BYTEORDER].param = 0x00; + } + + for (i = 0; slvif_cfgregs[i].bank != END_SLVCFG ; i++) { + ret = tuner_drv_hw_rmw_reg(slvif_cfgregs[i].bank, + slvif_cfgregs[i].adr, slvif_cfgregs[i].enabit, + slvif_cfgregs[i].param); + if (ret) { + pr_err("TS slave-IF configuration, failed.\n"); + return ret; + } + } + + ret = tuner_drv_hw_read_reg(Main2, 0x62, 1, &pbuf_max_size); + if (ret) { + pr_err("Read PKTMSIZE register, failed.\n"); + return ret; + } + if ((pbuf_max_size & 0x0F) == 0) + pr_debug("PKTMSIZE.MEMSIZE0[3:0] != 0x3.\n"); + + /* Interrupt setting */ + /* IBERINT_F */ + iberint.pack = 0; + iberint.set.mode = TUNER_EVENT_MODE_ADD; + iberint.set.intdef1 = 0x80; /* IBERINT */ + iberint.set.intset1 = 0x09; /* NINTEN, INTMD = 1 */ + ret = tuner_drv_hw_setev(&iberint); + if (ret) { + pr_err("tuner_drv_setev(F) failed.\n"); + return ret; + } + + /* Check byte order configuration. */ + ret = tuner_drv_hw_read_reg(Main2, 0x60, 1, &byte_order_set); + if (ret) { + pr_err("Main2 register read failed.\n"); + return ret; + } +#ifdef TUNER_CONFIG_SPI_DIVMSG + pr_debug("\n"); +#else + pr_debug("\n"); +#endif + pr_debug("\n", + tsif->spi_ts_bit_per_word); + pr_debug("\n", + byte_order_set, + (byte_order_set & 0x40) ? "LSB" : "MSB"); + return 0; +} + +/**************************************************************************//** + * Unregister the TS I/F driver + * + ******************************************************************************/ +void tuner_drv_hw_tsif_unregister(void) +{ + pr_debug("%s\n", __func__); + + spi_unregister_driver(&mn8855x_spi_driver); +} + +/**************************************************************************//** + * Get the DATAREADY flag + * + * This function return the DATAREADY flag of the Slave-I/F of + * tuner device. DATAREADY flag contain OVER/UNER-Run indicator. + * It is below there bit position. + * OVER-Run is bit-2. UNDER-Run is bit-1, DATA-Ready is bit-0. + * + * @retval >=0 DATAREADY flag (casted from uint8_t) + * @retval <0 error + ******************************************************************************/ +int tuner_drv_hw_tsif_get_dready(void) +{ + int ret; + /* breakcode 0xff, 0xfe, 0x81, 0x00 */ + uint8_t tx[12] = { 0xff, 0xfe, 0x81, 0x00, + 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t rx[12] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + struct spi_message msg; + struct spi_transfer xfer; + +#ifdef DSPI_DR_MESURE_DEBUG + struct timeval s1; + struct timeval t1; + unsigned long temp; +#endif + + memset(&xfer, 0, sizeof(struct spi_transfer)); + spi_message_init(&msg); + + xfer.tx_buf = CMDBUF_POS(tx); + xfer.rx_buf = CMDBUF_POS(rx); + xfer.len = CMDBUF_LEN(8); + xfer.bits_per_word = 8; + + spi_message_add_tail(&xfer, &msg); + mtxLock(); + +#ifdef DSPI_DR_MESURE_DEBUG + do_gettimeofday(&s1); +#endif + + ret = spi_sync(g_spi_drvdata->spi, &msg); + +#ifdef DSPI_DR_MESURE_DEBUG + do_gettimeofday(&t1); + temp = ((t1.tv_sec - s1.tv_sec) * 1000000 + (t1.tv_usec - s1.tv_usec)); + pr_err("dready() sa=%lu\n", temp); +#endif + + mtxUnlock(); + if (ret) { + pr_err("spi_sync() failed (rc:%d)\n", ret); + return ret; + } + + return (int) rx[11]; +} + +#if defined(TUNER_CONFIG_SPI_EXTREAD) || defined(TUNER_CONFIG_AES_ENABLE) +/**************************************************************************//** + * Set dummy cnt of SPI Extend Read + * + * This function set DMYCNT when use SPI EXTEND READ COMMAND for AES + * + * @retval >=0 + * @retval <0 error + ******************************************************************************/ +int tuner_drv_hw_tsif_set_dmycnt(unsigned int cnt) +{ + int ret; + uint8_t tx[12] = { + 0xff, 0xfe, 0x81, 0x00, /* breakcode 0xff, 0xfe, 0x81, 0x00 */ + 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + struct spi_message msg; + struct spi_transfer xfer; + + memset(&xfer, 0, sizeof(struct spi_transfer)); + spi_message_init(&msg); + + xfer.tx_buf = CMDBUF_POS(tx); + xfer.len = CMDBUF_LEN(8); + xfer.bits_per_word = 8; + +#ifdef TUNER_CONFIG_SPI_EDGE + tx[8] = (cnt & 0xf) | 0x80; +#else + tx[8] = cnt & 0xf; +#endif + spi_message_add_tail(&xfer, &msg); + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + mtxUnlock(); + if (ret) { + pr_err("spi_sync() failed (rc:%d)\n", ret); + return ret; + } + + return ret; +} +#endif + +/**************************************************************************//** + * Send the transaction command to synchronize slave I/F of tuner. + * + * This function send the packet synchronization command. + * It initialize the read pointer and clear the FIFO buffer. + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +int tuner_drv_hw_tsif_sync_pkt(void) +{ + int ret = 0; + /* breakcode 0xff, 0xfe, 0x81, 0x00 */ + uint8_t tx[8] = { 0xff, 0xfe, 0x81, 0x00, 0xd8, 0x00, 0x00, 0x00 }; + struct spi_message msg; + struct spi_transfer xfer; + + pr_debug("%s\n", __func__); + + memset(&xfer, 0, sizeof(struct spi_transfer)); + spi_message_init(&msg); + + xfer.tx_buf = CMDBUF_POS(tx); + xfer.len = CMDBUF_LEN(4); + xfer.bits_per_word = 8; + + spi_message_add_tail(&xfer, &msg); + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + mtxUnlock(); + if (ret) { + pr_err("spi_sync() failed (rc:%d)\n", ret); + return ret; + } + + return 0; +} + +/**************************************************************************//** + * Get the TS packets of the appointed number. + * + * @retval >=0 Normal end (number of the get packet) + * @retval <0 error (refer the errno) + * + * @param [in] num num of packets + * @param [out] pktbuf packet storage + * @param [in] pktsize packet size enumerator + ******************************************************************************/ +int tuner_drv_hw_tsif_get_pkts(struct _tsif_cntxt *tc) +{ + int ret; + struct spi_message msg; +#ifdef TUNER_CONFIG_SPI_DIVMSG + struct spi_message tsmsg; +#endif + struct spi_transfer xfer[2]; + int sum = 0; + struct _tuner_data_tsif *tsif = tc->tsif; + unsigned int ts_rdelay = 0; + + /* TS packet size: 188Byte, num of TS packets:256 */ + /* Break code0xff, 0xfe, 0x81, 0x00 + Packet Read commnad */ + uint8_t tx[9 + 17] = { 0xff, 0xfe, 0x81, 0x00, /* 4 byte length */ + /* 5 byte length command ex. 0x0b .. */ + SPI_READ_COMMAND, 0x00, 0x00, 0xFF, 0x00, + /* This 16 bytes is dummy cycles */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* for extend read command */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Last byte is for additional cycle in edge mode and + * extend read is enabled + */ + 0x00 }; +#ifdef SPI_GP_MESURE_DEBUG + struct timeval s1; + struct timeval t1; + unsigned long temp; +#endif + +#if defined(TUNER_CONFIG_SPI_EXTREAD) || defined(TUNER_CONFIG_AES_ENABLE) + ts_rdelay = ts_rdelay + SPI_TSREAD_DMYCNT; +#endif /* TUNER_CONFIG_SPI_EXTREAD */ +#ifdef TUNER_CONFIG_SPI_EDGE + ts_rdelay = ts_rdelay + 1; /* EDGE==1 */ +#endif /* TUNER_CONFIG_SPI_EDGE */ + + if (!g_spi_drvdata) { + pr_err("SPI I/F not active.\n"); + return -ENXIO; + } + if (!tc->pktbuf) { + pr_err("TS buffer not found.\n"); + return -EINVAL; + } + if (tc->tsif->ts_pkt_type == TUNER_DRV_TS_TSTAMP) { + pr_err("not support the Time-Stamp TS"); + return -EINVAL; + } + if (!tc->spibuf) { + pr_err("SPI buf not found.\n"); + return -EINVAL; + } + memset(tc->spibuf, 0, tc->ts_rx_size); + + memset(xfer, 0, sizeof(xfer)); + spi_message_init(&msg); + + tx[4 + 2] = (tc->ts_rxpkt_num - 1) >> 8; + tx[4 + 3] = (tc->ts_rxpkt_num - 1) & 0xff; + /* break | read mode | edge mode || ts_rdelay(=edge delay+DMYCNT delay) + * | nomral | off || 0 + * | nomral | on || 1 + * on | nomral | off || 0 + * on | nomral | on || 1 + * | extend | off || DMYCNT + * | extned | on || DMYCNT+1 + * on | extend | off || DMYCNT + * on | extend | on || DMYCNT+1 + */ + xfer[0].tx_buf = CMDBUF_POS(tx); + xfer[0].len = CMDBUF_LEN(5) + ts_rdelay; + xfer[0].bits_per_word = 8; + + spi_message_add_tail(&xfer[0], &msg); + + xfer[1].rx_buf = (void *) (tc->spibuf); + xfer[1].bits_per_word = tsif->spi_ts_bit_per_word; +#ifdef TUNER_CONFIG_SPI_DIVMSG + xfer[1].len = BUFLEN_ALIGN(tc->ts_rx_size); + spi_message_init(&tsmsg); + spi_message_add_tail(&xfer[1], &tsmsg); + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + if (ret) { + pr_err("spi_sync() failed (rc:%d)\n", ret); + mtxUnlock(); + return ret; + } + + ret = spi_sync(g_spi_drvdata->spi, &tsmsg); + mtxUnlock(); + if (ret) { + pr_err("spi_sync() failed (rc:%d)\n", ret); + return ret; + } +#else + xfer[1].len = tc->ts_rx_size; + spi_message_add_tail(&xfer[1], &msg); + + mtxLock(); + +#ifdef SPI_GP_MESURE_DEBUG + do_gettimeofday(&s1); +#endif + + ret = spi_sync(g_spi_drvdata->spi, &msg); + +#ifdef SPI_GP_MESURE_DEBUG + do_gettimeofday(&t1); + temp = ((t1.tv_sec - s1.tv_sec) * 1000000 + (t1.tv_usec - s1.tv_usec)); + pr_err("spi_sync() sa=%lu\n", temp); +#endif + + mtxUnlock(); + if (ret) { + pr_err("spi_sync() failed (rc:%d)\n", ret); + return ret; + } +#endif + + /* Plase add the code to transform endian , if you need */ + /* ---------------------------------------------------- */ + + /* ---------------------------------------------------- */ + + memcpy((void *) (tc->pktbuf + tc->pwr), + (void *) (tc->spibuf), tc->ts_rx_size); + tc->pwr += tc->ts_rx_size; + + if (tc->pwr == tc->ts_pktbuf_size) + tc->pwr = 0; + + return sum; +} + +/**************************************************************************//** + * probe function called by spi_register_driver() + * + * @retval 0 Normal end + * @retval <0 error (refer the errno) + * + * @param [in] spidev pointer to the "spi_device" structure + ******************************************************************************/ +static int tuner_drv_spi_probe(struct spi_device *spidev) +{ + int ret = 0; + struct spi_drvdata *drvdata; + + pr_debug("%s\n", __func__); + + if (g_spi_drvdata != NULL) { + pr_err("SPI I/F not active.\n"); + return -EBUSY; + } + if (spidev == NULL) { + pr_err("illegal argument.\n"); + return -EINVAL; + } + + drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->spi = spidev; + spin_lock_init(&drvdata->spi_lock); + spi_set_drvdata(spidev, drvdata); + g_spi_drvdata = drvdata; + + ret = spi_setup(spidev); + if (ret) { + pr_err("spi_setup() failed.\n"); + return ret; + } +#ifdef DEBUG + pr_info("max_speed_hz :%d\n", spidev->max_speed_hz); + pr_info("chip_select :%d\n", spidev->chip_select); + pr_info("mode :%d\n", spidev->mode); + pr_info("bits_per_word :%d\n", spidev->bits_per_word); + pr_info("irq :%d\n", spidev->irq); + pr_info("modalias :%s\n", spidev->modalias); +#endif + return ret; +} + +/**************************************************************************//** + * remove function called by spi_register_driver() + * + * @retval 0 Normal end + * @retval <0 error (refer the errno) + * + * @param [in] spidev pointer to the "spi_device" structure + ******************************************************************************/ +static int tuner_drv_spi_remove(struct spi_device *spidev) +{ + pr_debug("%s\n", __func__); + + spi_set_drvdata(spidev, NULL); + kfree(g_spi_drvdata); + g_spi_drvdata = NULL; + + return 0; +} + +/**************************************************************************//** + * TS read Calibration + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +#ifdef TUNER_CONFIG_SPI_EDGE +int tuner_drv_spi_calibration(void) +{ + int ret = 0; + /* breakcode 0xff, 0xfe, 0x81, 0x00 */ + uint8_t tx1[7 + 32] = { 0xff, 0xfe, 0x81, 0x00, + 0x4b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; /* Calibration command */ + uint8_t rx1[7 + 4 * 8] = { 0x00 }; /* Read calib. result */ + /* breakcode 0xff, 0xfe, 0x81, 0x00 */ + uint8_t tx2[12] = { 0xff, 0xfe, 0x81, 0x00, + 0x03, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* Delay set */ + struct spi_message msg; + struct spi_transfer xfer[3]; + int i; + int sp, ep, pos; + + pr_debug("%s\n", __func__); + + memset(xfer, 0, sizeof(xfer)); + spi_message_init(&msg); + + /* Calibration Command */ + xfer[0].tx_buf = CMDBUF_POS(tx1); + xfer[0].rx_buf = CMDBUF_POS(rx1); + xfer[0].len = CMDBUF_LEN(3+32); + xfer[0].bits_per_word = 8; + spi_message_add_tail(&xfer[0], &msg); + + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + mtxUnlock(); + if (ret) { + pr_err("spi_sync() failed (rc:%d)\n", ret); + return ret; + } + + pr_debug("\n"); + for (i = 7; i < 39; i += 4) { + pr_debug( + " (%1d) rx[%2d]:%02X, rx[%2d]:%02X, rx[%2d]:%02X, rx[%2d]:%02X\n", + (int)((i-7)/4), i+0, rx1[i+0], i+1, rx1[i+1], i+2, rx1[i+2], + i+3, rx1[i+3]); + } + + /* Calculation delay */ + sp = 0; + ep = 0; + for (i = 0; i < 8; i++) { + if (rx1[4 + 5 + i * 4] == 0x72) { + if (sp == 0) + sp = i + 1; + else + ep = i + 1; + } + } + + /* Delay set */ + pos = (int) ((sp + ep) / 2); + tx2[4 + 4] = pos; + pr_debug("sp(%d),ep(%d)==>pos: %d (edge_mode:%d)\n", + sp, ep, pos, g_edge_mode); + + memset(xfer, 0, sizeof(xfer)); + spi_message_init(&msg); + xfer[2].tx_buf = CMDBUF_POS(tx2); + xfer[2].len = CMDBUF_LEN(8); + xfer[2].bits_per_word = 8; + spi_message_add_tail(&xfer[2], &msg); + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + mtxUnlock(); + if (ret) { + pr_err("spi_sync() failed (rc:%d)\n", ret); + return ret; + } + + if (sp == 0) { + pr_err("spi_calibration() failed. sp = %d", sp); + return -EAGAIN; + } + return 0; +} +#endif + +/**************************************************************************//** + * EDGE mode setting + * + * @retval 0 normal + * @retval <0 error + ******************************************************************************/ +#ifdef TUNER_CONFIG_SPI_EDGE +int tuner_drv_spi_edge(int ctrl) +{ + int ret = 0; + /* breakcode 0xff, 0xfe, 0x81, 0x00 */ + uint8_t tx[12] = { 0xff, 0xfe, 0x81, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x00, + 0x00, 0x00, 0x00 }; + struct spi_message msg; + struct spi_transfer xfer; + + pr_debug("%s\n", __func__); + + memset(&xfer, 0, sizeof(struct spi_transfer)); + spi_message_init(&msg); + + tx[4 + 4] = (ctrl << 7) | SPI_TSREAD_DMYCNT; + + xfer.tx_buf = CMDBUF_POS(tx); + xfer.len = CMDBUF_LEN(8); + xfer.bits_per_word = 8; + spi_message_add_tail(&xfer, &msg); + mtxLock(); + ret = spi_sync(g_spi_drvdata->spi, &msg); + mtxUnlock(); + if (ret) { + pr_err("spi_sync() return with %d", ret); + return ret; + } + g_edge_mode = ctrl; + pr_debug("SPI EDGE mode (%d)", g_edge_mode); + return 0; +} +#endif + +/******************************************************************************* + * Copyright (c) 2015 Socionext Inc. + ******************************************************************************/ diff --git a/drivers/misc/oneseg_tuner_drv.c b/drivers/misc/oneseg_tuner_drv.c new file mode 100644 index 0000000000000000000000000000000000000000..275144c2dc9b1945d46705027708387ad44d8ce7 --- /dev/null +++ b/drivers/misc/oneseg_tuner_drv.c @@ -0,0 +1,476 @@ +/* drivers/misc/oneseg_tuner_drv.c + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define D_ONESEG_CONFIG_MODULE_NAME "Oneseg Tuner Driver" +#define D_ONESEG_CONFIG_MODULE_LICENCE "GPL" +#define D_ONESEG_CONFIG_DRIVER_NAME "onesegtuner_drv" +#define D_ONESEG_CONFIG_PLATFORM_DRIVER_NAME "onesegtuner_pdev" +#define D_ONESEG_CONFIG_SYSFS_DEV_NAME "onesegtuner_pdev" +#define D_ONESEG_CONFIG_CLASS_NAME "onesegtuner" +#define D_ONESEG_CONFIG_MATCH_TABLE "sony,vj190" +#define D_SPI_PLATFORM_DRIVER_NAME "oneseg_tuner_spi_dev" +#define D_SPI_CONFIG_MATCH_TABLE "sony,oneseg-tuner" + +#define D_ONESEG_CONFIG_DRV_MAJOR 110 +#define D_ONESEG_CONFIG_DRV_MINOR 210 +#define D_ONESEG_POWER_ON_WAIT_US 3000 +#define D_ONESEG_POWER_ON_WAIT_RANGE_US 3100 +#define D_ONESEG_RESET_ON_WAIT_US 1000 +#define D_ONESEG_RESET_ON_WAIT_RANGE_US 1100 +#define D_ONESEG_RESET_OFF_WAIT_US 1000 +#define D_ONESEG_RESET_OFF_WAIT_RANGE_US 1100 + +enum oneseg_gpio_id { + ONESEG_POWER_PIN = 0, + ONESEG_RESET_PIN, + ONESEG_INT_PIN, +}; + +static char const * const oneseg_gpio_rsrcs[] = { + "Oneseg tuner power", + "Oneseg tuner reset", + "Oneseg tuner int", +}; + +enum ONESEG_DRV_CTL { + ONESEG_DRV_CTL_POWON, + ONESEG_DRV_CTL_POWOFF, + ONESEG_DRV_CTL_RESET +}; + +enum ONESEG_DRV_IRQ { + ONESEG_DRV_IRQ_NOT_DETECTED, + ONESEG_DRV_IRQ_DETECTED, +}; + +struct oneseg_tuner_drvdata { + struct device *dev; + struct device sysfs_dev; + struct mutex mutex_lock; + unsigned int gpios[ARRAY_SIZE(oneseg_gpio_rsrcs)]; +}; + +struct g_oneseg_tuner_device { + struct mutex g_tuner_mutex; + unsigned long open_cnt; + struct platform_device *onesegtuner_device; + struct class *device_class; + u32 irq_flag; + wait_queue_head_t irq_wait_q; + int irq_num; +} oneseg_dev; + +static enum oneseg_gpio_id req_ids[] = { + ONESEG_POWER_PIN, + ONESEG_RESET_PIN, + ONESEG_INT_PIN, +}; + +static void oneseg_tunerpm_power_control(struct oneseg_tuner_drvdata + *drvdata, int on) +{ + gpio_set_value_cansleep(drvdata->gpios[ONESEG_POWER_PIN], on); +} + +static void oneseg_tunerpm_reset_control(struct oneseg_tuner_drvdata *drvdata, + int on) +{ + gpio_set_value_cansleep(drvdata->gpios[ONESEG_RESET_PIN], on); +} + +static int oneseg_dev_init(struct platform_device *pdev, + struct oneseg_tuner_drvdata *drvdata) +{ + int i, ret, gpio; + unsigned int flags; + struct device_node *of_node = pdev->dev.of_node; + + mutex_init(&drvdata->mutex_lock); + + for (i = 0; i < ARRAY_SIZE(oneseg_gpio_rsrcs); i++) { + gpio = of_get_gpio_flags(of_node, i, &flags); + if (!gpio_is_valid(gpio)) { + ret = -EINVAL; + goto error_gpio; + } + drvdata->gpios[i] = gpio; + } + + for (i = 0; i < ARRAY_SIZE(req_ids); i++) { + ret = gpio_request(drvdata->gpios[req_ids[i]], + oneseg_gpio_rsrcs[req_ids[i]]); + if (ret) + goto error_gpio_request; + } + + oneseg_tunerpm_power_control(drvdata, 0); + oneseg_tunerpm_reset_control(drvdata, 0); + + return 0; + +error_gpio_request: + for (i--; i >= 0; i--) + gpio_free(drvdata->gpios[req_ids[i]]); +error_gpio: + return ret; +} + +static void oneseg_dev_finalize(struct oneseg_tuner_drvdata *drvdata) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(req_ids); i++) + gpio_free(drvdata->gpios[req_ids[i]]); +} + +static int tuner_drv_ctl_power(struct oneseg_tuner_drvdata *drvdata, int data) +{ + switch (data) { + case ONESEG_DRV_CTL_POWON: + mutex_lock(&drvdata->mutex_lock); + oneseg_tunerpm_power_control(drvdata, 1); + mutex_unlock(&drvdata->mutex_lock); + usleep_range(D_ONESEG_POWER_ON_WAIT_US, + D_ONESEG_POWER_ON_WAIT_RANGE_US); + break; + case ONESEG_DRV_CTL_RESET: + mutex_lock(&drvdata->mutex_lock); + oneseg_tunerpm_reset_control(drvdata, 1); + mutex_unlock(&drvdata->mutex_lock); + usleep_range(D_ONESEG_RESET_ON_WAIT_US, + D_ONESEG_RESET_ON_WAIT_RANGE_US); + break; + case ONESEG_DRV_CTL_POWOFF: + mutex_lock(&drvdata->mutex_lock); + usleep_range(D_ONESEG_RESET_OFF_WAIT_US, + D_ONESEG_RESET_OFF_WAIT_RANGE_US); + oneseg_tunerpm_reset_control(drvdata, 0); + oneseg_tunerpm_power_control(drvdata, 0); + mutex_unlock(&drvdata->mutex_lock); + break; + default: + return -EINVAL; + } + return 0; +} + +irqreturn_t tuner_interrupt(int irq, void *dev_id) +{ + if (oneseg_dev.irq_flag == ONESEG_DRV_IRQ_NOT_DETECTED) { + oneseg_dev.irq_flag = ONESEG_DRV_IRQ_DETECTED; + wake_up_interruptible(&oneseg_dev.irq_wait_q); + } + return IRQ_HANDLED; +} + +static int tuner_drv_set_interrupt(int int_num) +{ + int ret; + + oneseg_dev.irq_num = gpio_to_irq(int_num); + ret = request_threaded_irq(oneseg_dev.irq_num, tuner_interrupt, + NULL, IRQF_TRIGGER_RISING, D_ONESEG_CONFIG_CLASS_NAME, NULL); + if (ret) { + gpio_free(int_num); + return -EINVAL; + } + return 0; +} + +static void tuner_drv_release_interrupt(void) +{ + free_irq(oneseg_dev.irq_num, NULL); +} + +static ssize_t tuner_module_power_ctrl(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct oneseg_tuner_drvdata *drvdata = dev_get_drvdata(dev); + unsigned long value; + int ret; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (!value) { + ret = tuner_drv_ctl_power(drvdata, ONESEG_DRV_CTL_POWON); + if (ret) + return -EINVAL; + ret = tuner_drv_ctl_power(drvdata, ONESEG_DRV_CTL_RESET); + if (ret) { + tuner_drv_ctl_power(drvdata, ONESEG_DRV_CTL_POWOFF); + return -EINVAL; + } + } else { + tuner_drv_ctl_power(drvdata, ONESEG_DRV_CTL_POWOFF); + } + return count; +} + +static ssize_t tuner_module_irq_ctrl(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long value; + struct oneseg_tuner_drvdata *drvdata = dev_get_drvdata(dev); + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (!value) { + if (tuner_drv_set_interrupt(drvdata->gpios[ONESEG_INT_PIN])) + return -EINVAL; + } else { + tuner_drv_release_interrupt(); + oneseg_dev.irq_flag = ONESEG_DRV_IRQ_NOT_DETECTED; + } + + return count; +} + +static ssize_t tuner_module_irq_detect_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + wait_event_interruptible(oneseg_dev.irq_wait_q, + (oneseg_dev.irq_flag == ONESEG_DRV_IRQ_DETECTED)); + return snprintf(buf, 1, "%d", oneseg_dev.irq_flag); +} + +static ssize_t tuner_module_irq_detect_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + oneseg_dev.irq_flag = ONESEG_DRV_IRQ_NOT_DETECTED; + return count; +} + +static int tuner_module_entry_open(struct inode *inode, struct file *file) +{ + if (oneseg_dev.open_cnt > 0) + return -EBUSY; + oneseg_dev.open_cnt++; + + oneseg_dev.irq_flag = ONESEG_DRV_IRQ_NOT_DETECTED; + + return 0; +} + +static int tuner_module_entry_close(struct inode *inode, struct file *file) +{ + struct devone_data *dev; + + if (oneseg_dev.open_cnt <= 0) + return -ESRCH; + oneseg_dev.open_cnt--; + + if (oneseg_dev.open_cnt == 0) { + if (!file) + return -ESRCH; + dev = file->private_data; + } + + return 0; +} + +static struct device_attribute tuner_sysfs_attrs[] = { + __ATTR(oneseg_power_ctrl, S_IWUSR, 0, tuner_module_power_ctrl), + __ATTR(oneseg_irq_ctrl, S_IWUSR, 0, tuner_module_irq_ctrl), + __ATTR(oneseg_irq, S_IWUSR | S_IRUSR, tuner_module_irq_detect_read, + tuner_module_irq_detect_write), +}; + +static const struct file_operations tuner_file_operations = { + .owner = THIS_MODULE, + .open = tuner_module_entry_open, + .release = tuner_module_entry_close +}; + +static int oneseg_tuner_probe(struct platform_device *pdev) +{ + int ret; + int i; + struct device *dev = NULL; + struct oneseg_tuner_drvdata *drvdata; + + oneseg_dev.onesegtuner_device = platform_device_alloc( + D_ONESEG_CONFIG_CLASS_NAME, -1); + + if (!oneseg_dev.onesegtuner_device) { + ret = -ENOMEM; + goto err_platform_device_alloc; + } + + ret = platform_device_add(oneseg_dev.onesegtuner_device); + if (ret) + goto err_platform_device_add; + + oneseg_dev.device_class = class_create(THIS_MODULE, + D_ONESEG_CONFIG_CLASS_NAME); + if (IS_ERR(oneseg_dev.device_class)) { + ret = PTR_ERR(oneseg_dev.device_class); + goto err_class_create; + } + + dev = device_create(oneseg_dev.device_class, NULL, + MKDEV(D_ONESEG_CONFIG_DRV_MAJOR, D_ONESEG_CONFIG_DRV_MINOR), + NULL, D_ONESEG_CONFIG_CLASS_NAME); + + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + goto err_device_create; + } + + drvdata = kzalloc(sizeof(struct oneseg_tuner_drvdata), GFP_KERNEL); + if (!drvdata) { + ret = -ENOMEM; + goto err_alloc_data; + } + + drvdata->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, drvdata); + drvdata->sysfs_dev.init_name = D_ONESEG_CONFIG_SYSFS_DEV_NAME; + dev_set_drvdata(&drvdata->sysfs_dev, drvdata); + ret = device_register(&drvdata->sysfs_dev); + if (ret) + goto err_set_dev; + + ret = register_chrdev(D_ONESEG_CONFIG_DRV_MAJOR, + D_ONESEG_CONFIG_DRIVER_NAME, &tuner_file_operations); + if (ret < 0) + goto err_register_device; + + ret = oneseg_dev_init(pdev, drvdata); + if (ret) + goto err_gpio_init; + + oneseg_dev.open_cnt = 0; + + for (i = 0; i < ARRAY_SIZE(tuner_sysfs_attrs); i++) { + ret = device_create_file(&drvdata->sysfs_dev, + &tuner_sysfs_attrs[i]); + if (ret) { + for (; i >= 0; --i) + device_remove_file(&drvdata->sysfs_dev, + &tuner_sysfs_attrs[i]); + goto err_create_file; + } + } + + mutex_init(&oneseg_dev.g_tuner_mutex); + + init_waitqueue_head(&oneseg_dev.irq_wait_q); + + if (tuner_drv_set_interrupt(drvdata->gpios[ONESEG_INT_PIN])) + goto err_irq_set; + return 0; + +err_irq_set: +err_create_file: +err_gpio_init: + unregister_chrdev(D_ONESEG_CONFIG_DRV_MAJOR, + D_ONESEG_CONFIG_DRIVER_NAME); +err_register_device: + device_unregister(&drvdata->sysfs_dev); +err_set_dev: + kzfree(drvdata); +err_alloc_data: + device_destroy(oneseg_dev.device_class, MKDEV(D_ONESEG_CONFIG_DRV_MAJOR, + D_ONESEG_CONFIG_DRV_MINOR)); +err_device_create: + class_destroy(oneseg_dev.device_class); +err_class_create: + platform_device_del(oneseg_dev.onesegtuner_device); +err_platform_device_add: + platform_device_put(oneseg_dev.onesegtuner_device); +err_platform_device_alloc: + return ret; +} + +static int oneseg_tuner_remove(struct platform_device *pdev) +{ + struct oneseg_tuner_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + oneseg_dev_finalize(drvdata); + unregister_chrdev(D_ONESEG_CONFIG_DRV_MAJOR, + D_ONESEG_CONFIG_DRIVER_NAME); + + return 0; +} + +static void oneseg_tuner_shutdown(struct platform_device *pdev) +{ + device_destroy(oneseg_dev.device_class, MKDEV(D_ONESEG_CONFIG_DRV_MAJOR, + D_ONESEG_CONFIG_DRV_MINOR)); + class_destroy(oneseg_dev.device_class); + platform_device_unregister(oneseg_dev.onesegtuner_device); +} + +static const struct of_device_id vj190_match_table[] = { +{ .compatible = D_ONESEG_CONFIG_MATCH_TABLE, +}, +{} +}; + +static struct platform_driver onesegtuner_driver = { + .probe = oneseg_tuner_probe, + .remove = oneseg_tuner_remove, + .shutdown = oneseg_tuner_shutdown, + .driver = { + .name = D_ONESEG_CONFIG_PLATFORM_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = vj190_match_table, + }, +}; + +static int __init oneseg_drv_start(void) +{ + return platform_driver_register(&onesegtuner_driver); +} + +static void __exit oneseg_drv_end(void) +{ + platform_driver_unregister(&onesegtuner_driver); +} + +MODULE_LICENSE(D_ONESEG_CONFIG_MODULE_LICENCE); +MODULE_DESCRIPTION(D_ONESEG_CONFIG_MODULE_NAME); + +module_init(oneseg_drv_start); +module_exit(oneseg_drv_end); diff --git a/drivers/misc/pn547.c b/drivers/misc/pn547.c new file mode 100644 index 0000000000000000000000000000000000000000..9de3706fd7bc40a42c80f11a0ed93a007085b11f --- /dev/null +++ b/drivers/misc/pn547.c @@ -0,0 +1,695 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PN547_WAIT_VENENABLE 10 +#define PN547_WAIT_VENDISABLE 60 + +#define PN547_WAKE_LOCK_TIMEOUT (HZ) +#define MAX_I2C_RETRY_COUNT 5 +#define MAX_NORMAL_FRAME_SIZE (255 + 3) +#define MAX_FIRMDL_FRAME_SIZE (1023 + 5) + +#define PN547_RES_READY_TIMEOUT_NORMAL (HZ * 2) +#define PN547_RES_READY_TIMEOUT_FWDL (HZ * 15) +#define PN547_RES_READY_SIZE 6 +#define PN547_RES_READY "ready" +#define PN547_RES_NOT_READY "not_ready" + +#ifdef DEBUG_DETAIL +#define DETAIL_LOG_SIZE 3 +#endif + +static DEFINE_MUTEX(lock); + +static const char * const init_deinit_cmds[] = { + [PN547_INIT] = "pn547_init", + [PN547_DEINIT] = "pn547_deinit", +}; + +static const char * const set_pwr_cmds[] = { + [PN547_SET_PWR_OFF] = "pn547_set_pwr_off", + [PN547_SET_PWR_ON] = "pn547_set_pwr_on", + [PN547_SET_PWR_FWDL] = "pn547_set_pwr_fwdl", +}; + +struct pn547_dev { + wait_queue_head_t wq; + struct wake_lock wake_lock; + struct device *dev; + struct i2c_client *i2c_client; + struct pn547_i2c_platform_data *pdata; + struct pinctrl *pinctrl; + enum pn547_state state; + bool busy; + u16 req_size; + atomic_t res_ready; +}; + +static void dump_buf(struct pn547_dev *d, u8 *buf, int size) +{ +#ifdef DEBUG_DETAIL + if (d->state == PN547_STATE_ON || d->state == PN547_STATE_FWDL) { + int i, size, p = 0; + bool fwdl; + char *s; + + fwdl = d->state == PN547_STATE_FWDL; + size = fwdl ? MAX_FIRMDL_FRAME_SIZE : MAX_NORMAL_FRAME_SIZE; + s = kzalloc(size * DETAIL_LOG_SIZE + 1); + for (i = 0; i < size; i++) + p += snprintf(s + p, sizeof(s) - p, "%02x ", buf[i]); + dev_dbg(d->dev, "%s\n", s); + kzfree(s); + } +#endif +} + +static irqreturn_t pn547_dev_irq_handler(int irq, void *dev_info) +{ + struct pn547_dev *d = dev_info; + + dev_dbg(d->dev, "%s: interruption\n", __func__); + mutex_lock(&lock); + wake_lock_timeout(&d->wake_lock, PN547_WAKE_LOCK_TIMEOUT); + atomic_set(&d->res_ready, 1); + wake_up_interruptible(&d->wq); + mutex_unlock(&lock); + return IRQ_HANDLED; +} + +static int pn547_pinctrl_config(struct pn547_dev *dev, uint8_t active) +{ + struct pinctrl_state *state; + const char *name = active ? "pn547-active" : "pn547-inactive"; + + state = pinctrl_lookup_state(dev->pinctrl, name); + if (IS_ERR(state)) { + dev_err(dev->dev, + "%s: pinctrol lookup state failed\n", + __func__); + return PTR_ERR(state); + } + + return pinctrl_select_state(dev->pinctrl, state); +} + +static int pn547_dev_chip_config(enum pn547_state state, struct pn547_dev *dev) +{ + int ret = 0; + + /* Activate pinctrol before bit banging. */ + ret = pn547_pinctrl_config(dev, 1); + if (ret) { + dev_err(dev->dev, + "%s: pinctrol failed on chip configuration %d\n", + __func__, ret); + goto err; + } + + switch (state) { + case PN547_STATE_OFF: + gpio_set_value_cansleep(dev->pdata->fwdl_en_gpio, 0); + gpio_set_value_cansleep(dev->pdata->ven_gpio, 0); + msleep(PN547_WAIT_VENDISABLE); + + /* Suspend pinctrol when PN547 is turned off. */ + ret = pn547_pinctrl_config(dev, 0); + if (ret) { + dev_err(dev->dev, + "%s: pinctrol failed on PN547_STATE_OFF %d\n", + __func__, ret); + goto err; + } + break; + case PN547_STATE_ON: + gpio_set_value_cansleep(dev->pdata->fwdl_en_gpio, 0); + gpio_set_value_cansleep(dev->pdata->ven_gpio, 1); + msleep(PN547_WAIT_VENENABLE); + break; + case PN547_STATE_FWDL: + gpio_set_value_cansleep(dev->pdata->ven_gpio, 1); + gpio_set_value_cansleep(dev->pdata->fwdl_en_gpio, 1); + msleep(PN547_WAIT_VENENABLE); + gpio_set_value_cansleep(dev->pdata->ven_gpio, 0); + msleep(PN547_WAIT_VENENABLE); + gpio_set_value_cansleep(dev->pdata->ven_gpio, 1); + msleep(PN547_WAIT_VENENABLE); + break; + default: + dev_err(dev->dev, "%s: undefined state %d\n", __func__, state); + return -EINVAL; + } + return 0; + +err: + return ret; +} + +static int pn547_parse_dt(struct device *dev, + struct pn547_i2c_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + int ret = 0; + + ret = of_get_named_gpio(np, "nxp,irq_gpio", 0); + if (ret < 0) { + dev_err(dev, "failed to get \"nxp,irq_gpio\"\n"); + goto err; + } + pdata->irq_gpio = ret; + + ret = of_get_named_gpio(np, "nxp,dwld_en", 0); + if (ret < 0) { + dev_err(dev, "failed to get \"nxp,dwld_en\"\n"); + goto err; + } + pdata->fwdl_en_gpio = ret; + + ret = of_get_named_gpio(np, "nxp,ven", 0); + if (ret < 0) { + dev_err(dev, "failed to get \"nxp,ven\"\n"); + goto err; + } + pdata->ven_gpio = ret; + +err: + return ret; +} + +static int pn547_gpio_request(struct device *dev, + struct pn547_i2c_platform_data *pdata) +{ + int ret; + + ret = gpio_request(pdata->irq_gpio, "pn547_irq"); + if (ret) + goto err_irq; + ret = gpio_request(pdata->fwdl_en_gpio, "pn547_fw"); + if (ret) + goto err_fwdl_en; + ret = gpio_request(pdata->ven_gpio, "pn547_ven"); + if (ret) + goto err_ven; + return 0; + +err_ven: + gpio_free(pdata->fwdl_en_gpio); +err_fwdl_en: + gpio_free(pdata->irq_gpio); +err_irq: + dev_err(dev, "%s: gpio request err %d\n", __func__, ret); + return ret; +} + +static void pn547_gpio_release(struct pn547_i2c_platform_data *pdata) +{ + gpio_free(pdata->ven_gpio); + gpio_free(pdata->irq_gpio); + gpio_free(pdata->fwdl_en_gpio); +} + +static void pn547_pinctrl_destroy(struct pn547_dev *dev) +{ + int ret = 0; + + ret = pn547_pinctrl_config(dev, 0); + if (ret) + dev_err(dev->dev, "%s: pinctrol failed on destroy %d\n", + __func__, ret); + + devm_pinctrl_put(dev->pinctrl); +} + +static ssize_t pn547_dev_recv_resp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pn547_dev *d = dev_get_drvdata(dev); + int ret = 0, retry_count = 0, maxlen; + bool fwdl; + + if (!d) + return -ENODEV; + + mutex_lock(&lock); + fwdl = d->state == PN547_STATE_FWDL; + maxlen = fwdl ? MAX_FIRMDL_FRAME_SIZE : MAX_NORMAL_FRAME_SIZE; + if (d->req_size > maxlen) + d->req_size = maxlen; + atomic_set(&d->res_ready, 0); +retry: + ret = i2c_master_recv(d->i2c_client, buf, d->req_size); + if (ret == -ENODEV || ret == -ENOTCONN || ret == -EIO) { + retry_count++; + if (retry_count > MAX_I2C_RETRY_COUNT) { + dev_err(d->dev, "%s: i2c err %d, retry count expired\n", + __func__, ret); + goto exit; + } + usleep_range(10000, 11000); + goto retry; + } + + if (ret < 0) { + dev_err(d->dev, "%s: i2c err %d\n", __func__, ret); + goto exit; + } + + if (ret > d->req_size) { + dev_err(d->dev, "%s: i2c err %d\n", __func__, ret); + ret = -EIO; + goto exit; + } + dump_buf(d, buf, ret); +exit: + mutex_unlock(&lock); + return ret; +} + +static ssize_t pn547_dev_recv_resp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct pn547_dev *d = dev_get_drvdata(dev); + + if (!d) + return -ENODEV; + + mutex_lock(&lock); + memcpy(&d->req_size, buf, size); + dev_dbg(d->dev, "%s: req_size = %d\n", __func__, d->req_size); + mutex_unlock(&lock); + return 0; +} + +static ssize_t pn547_dev_res_ready_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pn547_dev *d = dev_get_drvdata(dev); + bool state = false; + + if (!d) + return -ENODEV; + + dev_dbg(d->dev, "%s: res_ready_show enter\n", __func__); + + wait_event_interruptible_timeout(d->wq, atomic_read(&d->res_ready), + d->state == PN547_STATE_FWDL ? + PN547_RES_READY_TIMEOUT_FWDL : PN547_RES_READY_TIMEOUT_NORMAL); + if (atomic_read(&d->res_ready)) + state = true; + + dev_dbg(d->dev, "%s: res_ready_show exit\n", __func__); + return snprintf(buf, PN547_RES_READY_SIZE, "%s", + state ? PN547_RES_READY : PN547_RES_NOT_READY); +} + +static ssize_t pn547_dev_send_cmd_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct pn547_dev *d = dev_get_drvdata(dev); + int ret = 0, retry_count = 0, maxlen; + bool fwdl; + + if (!d) + return -ENODEV; + + mutex_lock(&lock); + if (!size) + goto exit; + + fwdl = d->state == PN547_STATE_FWDL; + maxlen = fwdl ? MAX_FIRMDL_FRAME_SIZE : MAX_NORMAL_FRAME_SIZE; + if (size > maxlen) + size = maxlen; +retry: + ret = i2c_master_send(d->i2c_client, buf, size); + if (ret == -ENODEV || ret == -ENOTCONN) { + retry_count++; + if (retry_count > MAX_I2C_RETRY_COUNT) { + dev_err(d->dev, "%s: i2c err %d, retry count expired\n", + __func__, ret); + goto exit; + } + usleep_range(10000, 11000); + goto retry; + } + + if (ret < 0) { + dev_err(d->dev, "%s: i2c err %d\n", __func__, ret); + goto exit; + } + dev_dbg(d->dev, "%s: %d bytes write\n", __func__, ret); + dump_buf(d, (u8 *)buf, ret); +exit: + mutex_unlock(&lock); + return ret; +} + +static ssize_t pn547_dev_init_deinit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct pn547_dev *d = dev_get_drvdata(dev); + + if (!d) + return -ENODEV; + + mutex_lock(&lock); + if (!strncmp(buf, init_deinit_cmds[PN547_INIT], PAGE_SIZE)) { + dev_dbg(d->dev, "%s: PN547_INIT\n", __func__); + if (d->busy) { + mutex_unlock(&lock); + return -EBUSY; + } + d->busy = true; + } else if (!strncmp(buf, init_deinit_cmds[PN547_DEINIT], PAGE_SIZE)) { + dev_dbg(d->dev, "%s: PN547_DEINIT\n", __func__); + if (atomic_read(&d->res_ready)) + dev_dbg(d->dev, "%s: interruption is ignored\n", + __func__); + atomic_set(&d->res_ready, 0); + d->busy = false; + } + mutex_unlock(&lock); + return 0; +} + +static ssize_t pn547_dev_set_pwr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct pn547_dev *d = dev_get_drvdata(dev); + int state, ret = 0; + + disable_irq(d->i2c_client->irq); + mutex_lock(&lock); + if (!strncmp(buf, set_pwr_cmds[PN547_SET_PWR_OFF], PAGE_SIZE)) { + dev_dbg(d->dev, "%s: PN547_SET_PWR_OFF\n", __func__); + state = PN547_STATE_OFF; + } else if (!strncmp(buf, set_pwr_cmds[PN547_SET_PWR_ON], PAGE_SIZE)) { + dev_dbg(d->dev, "%s: PN547_SET_PWR_ON\n", __func__); + state = PN547_STATE_ON; + } else if (!strncmp(buf, set_pwr_cmds[PN547_SET_PWR_FWDL], PAGE_SIZE)) { + dev_dbg(d->dev, "%s: PN547_SET_PWR_FWDL\n", __func__); + state = PN547_STATE_FWDL; + } else { + dev_err(d->dev, "%s: illegal command\n", __func__); + ret = -EINVAL; + } + + if (!ret) { + ret = pn547_dev_chip_config(state, d); + if (IS_ERR_VALUE(ret)) { + dev_err(d->dev, "%s: chip config err %d\n", + __func__, ret); + goto exit; + } + if (d->state != state) { + d->state = state; + atomic_set(&d->res_ready, 0); + } + } else { + dev_err(d->dev, "%s failed\n", __func__); + } +exit: + mutex_unlock(&lock); + enable_irq(d->i2c_client->irq); + return strnlen(buf, PAGE_SIZE); +} + +static struct device_attribute pn547_sysfs_attrs[] = { + __ATTR(init_deinit, S_IWUSR, NULL, pn547_dev_init_deinit_store), + __ATTR(set_pwr, S_IWUSR, NULL, pn547_dev_set_pwr_store), + __ATTR(res_ready, S_IRUSR, pn547_dev_res_ready_show, NULL), + __ATTR(send_cmd, S_IWUSR, NULL, pn547_dev_send_cmd_store), + __ATTR(recv_rsp, S_IRUSR | S_IWUSR, pn547_dev_recv_resp_show, + pn547_dev_recv_resp_store), +}; + +static int pn547_dev_create_sysfs_entries(struct i2c_client *dev) +{ + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(pn547_sysfs_attrs); i++) { + ret = device_create_file(&dev->dev, &pn547_sysfs_attrs[i]); + if (ret) { + for (; i >= 0; i--) + device_remove_file(&dev->dev, + &pn547_sysfs_attrs[i]); + goto exit; + } + } +exit: + return ret; +} + +static void pn547_dev_remove_sysfs_entries(struct i2c_client *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pn547_sysfs_attrs); i++) + device_remove_file(&dev->dev, &pn547_sysfs_attrs[i]); +} + +static int pn547_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pn547_dev *dev; + struct pn547_i2c_platform_data *pdata; + struct pinctrl *pinctrl; + struct clk *nfc_clk = NULL; + int ret = 0; + + pdata = kzalloc(sizeof(struct pn547_i2c_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "failed to get allocate memory\n"); + ret = -ENOMEM; + goto probe_pdata; + } + + pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR(pinctrl)) { + dev_err(&client->dev, "devm_pinctrl_get error\n"); + goto probe_pinctrl; + } + + ret = pn547_parse_dt(&client->dev, pdata); + if (ret < 0) { + dev_err(&client->dev, "failed to parse device tree: %d\n", ret); + goto probe_parse_dt; + } + + ret = pn547_gpio_request(&client->dev, pdata); + if (ret) { + dev_err(&client->dev, "failed to request gpio\n"); + goto probe_gpio_request; + } + dev_dbg(&client->dev, "%s:\n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "%s: i2c check failed\n", __func__); + ret = -ENODEV; + goto probe_i2c; + } + + dev = kzalloc(sizeof(struct pn547_dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "%s: no memory\n", __func__); + ret = -ENOMEM; + goto probe_mem; + } + dev->i2c_client = client; + dev->dev = &client->dev; + dev->pdata = pdata; + dev->pinctrl = pinctrl; + init_waitqueue_head(&dev->wq); + wake_lock_init(&dev->wake_lock, WAKE_LOCK_SUSPEND, "pn547"); + i2c_set_clientdata(client, dev); + dev->state = PN547_STATE_UNKNOWN; + + ret = request_threaded_irq(client->irq, NULL, pn547_dev_irq_handler, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, client->name, dev); + if (IS_ERR_VALUE(ret)) { + dev_err(&client->dev, "%s: irq request err %d\n", + __func__, ret); + goto probe_irq; + } + + nfc_clk = clk_get(&client->dev, "nfc_clk"); + if (IS_ERR(nfc_clk)) { + dev_err(&client->dev, "Couldn't get nfc_clk\n"); + goto probe_clk; + } + ret = clk_prepare_enable(nfc_clk); + if (ret) { + dev_err(&client->dev, "nfc_clk enable is failed\n"); + goto probe_clk_enable; + } + + ret = pn547_dev_create_sysfs_entries(dev->i2c_client); + if (IS_ERR_VALUE(ret)) { + dev_err(&client->dev, "%s: create sysfs entries err %d\n", + __func__, ret); + goto probe_sysfs; + } + return ret; + +probe_sysfs: + free_irq(client->irq, dev); +probe_clk_enable: + clk_put(nfc_clk); +probe_clk: +probe_irq: + i2c_set_clientdata(client, NULL); + wake_lock_destroy(&dev->wake_lock); + kzfree(dev); +probe_mem: +probe_i2c: + pn547_gpio_release(pdata); +probe_gpio_request: +probe_parse_dt: + devm_pinctrl_put(pinctrl); +probe_pinctrl: + kzfree(pdata); +probe_pdata: + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + return ret; +} + +static int pn547_remove(struct i2c_client *client) +{ + struct pn547_dev *d = i2c_get_clientdata(client); + + pn547_dev_remove_sysfs_entries(client); + free_irq(client->irq, d); + i2c_set_clientdata(client, NULL); + wake_lock_destroy(&d->wake_lock); + pn547_pinctrl_destroy(d); + pn547_gpio_release(d->pdata); + kzfree(d->pdata); + kzfree(d); + return 0; +} + +static int pn547_pm_suspend(struct device *dev) +{ + int ret; + struct pn547_dev *d = dev_get_drvdata(dev); + + dev_dbg(d->dev, "%s:\n", __func__); + if (!mutex_trylock(&lock)) + return -EAGAIN; + if (d->busy) { + if (atomic_read(&d->res_ready)) { + wake_lock_timeout(&d->wake_lock, + PN547_WAKE_LOCK_TIMEOUT); + mutex_unlock(&lock); + return -EAGAIN; + } + ret = irq_set_irq_wake(d->i2c_client->irq, 1); + if (IS_ERR_VALUE(ret)) + dev_err(dev, "%s: irq wake err %d\n", __func__, ret); + } + mutex_unlock(&lock); + return 0; +} + +static int pn547_pm_resume(struct device *dev) +{ + struct pn547_dev *d = dev_get_drvdata(dev); + int ret; + + dev_dbg(d->dev, "%s:\n", __func__); + mutex_lock(&lock); + if (d->busy) { + ret = irq_set_irq_wake(d->i2c_client->irq, 0); + if (IS_ERR_VALUE(ret)) + dev_err(dev, "%s: irq wake err %d\n", __func__, ret); + } + mutex_unlock(&lock); + return 0; +} + +static const struct i2c_device_id pn547_id[] = { + { PN547_DEVICE_NAME, 0 }, + { }, +}; + +static struct of_device_id pn547_match_table[] = { + { .compatible = "nxp,pn547", }, + { }, +}; + +static const struct dev_pm_ops pn547_pm_ops = { + .suspend = pn547_pm_suspend, + .resume = pn547_pm_resume, +}; + +static struct i2c_driver pn547_driver = { + .id_table = pn547_id, + .probe = pn547_probe, + .remove = pn547_remove, + .driver = { + .owner = THIS_MODULE, + .name = PN547_DEVICE_NAME, + .pm = &pn547_pm_ops, + .of_match_table = pn547_match_table, + }, +}; + +static int __init pn547_dev_init(void) +{ + return i2c_add_driver(&pn547_driver); +} + +static void __exit pn547_dev_exit(void) +{ + i2c_del_driver(&pn547_driver); +} + +module_init(pn547_dev_init); +module_exit(pn547_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN547 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/powerkey_forcecrash.c b/drivers/misc/powerkey_forcecrash.c new file mode 100644 index 0000000000000000000000000000000000000000..a8f2ab62cc23a364b89dc042a6a78f86bef6b1cc --- /dev/null +++ b/drivers/misc/powerkey_forcecrash.c @@ -0,0 +1,168 @@ +/* + * drivers/misc/powerkey_forcecrash.c + * + * 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. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FORCE_CRASH_TIMEOUT 10 +static struct timer_list forcecrash_timer; + +#define PKEY_FORCECRASH_DEV_NAME "powerkey_forcecrash" +static struct wake_lock powerkey_lock; + +static int forcecrash_on; +module_param(forcecrash_on, int, S_IRUGO | S_IWUSR); + +static void forcecrash_timeout(unsigned long data) +{ + panic("Force crash triggered!!!\n"); +} + +static void forcecrash_timer_setup(bool key_pressed) +{ + if (!forcecrash_on) + return; + + if (key_pressed) { + pr_debug("Power key pressed..\n"); + mod_timer(&forcecrash_timer, + jiffies + FORCE_CRASH_TIMEOUT * HZ); + wake_lock(&powerkey_lock); + } else { + pr_debug("released.\n"); + del_timer(&forcecrash_timer); + wake_unlock(&powerkey_lock); + } +} + +static void powerkey_input_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + switch (code) { + case KEY_POWER: + forcecrash_timer_setup(value); + break; + default: + break; + } +} + +static const char *powerkey_match_tbl[] = { + "qpnp_pon", + NULL +}; + +static bool powerkey_input_match(struct input_handler *handler, + struct input_dev *dev) +{ + const char *match = powerkey_match_tbl[0]; + + while (*match) { + size_t len = strlen(match); + if (!strncmp(dev->name, match, len)) + return true; + match++; + } + + pr_info("Ignoring %s handle for %s\n", handler->name, dev->name); + + return false; +} + +static int powerkey_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "powerkey_handle"; + pr_info("registering %s handle for %s\n", handle->name, dev->name); + + error = input_register_handle(handle); + if (error) + goto err2; + + error = input_open_device(handle); + if (error) + goto err1; + + return 0; +err1: + input_unregister_handle(handle); +err2: + kfree(handle); + return error; +} + +static void powerkey_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id input_dev_ids[] = { + /* Only Powerkey inputs */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER) }, + }, + { }, +}; + +static struct input_handler powerkey_input_handler = { + .event = powerkey_input_event, + .match = powerkey_input_match, + .connect = powerkey_input_connect, + .disconnect = powerkey_input_disconnect, + .name = "powerkey_handler", + .id_table = input_dev_ids, +}; + +static int __init powerkey_forcecrash_init(void) +{ + init_timer(&forcecrash_timer); + forcecrash_timer.function = forcecrash_timeout; + wake_lock_init(&powerkey_lock, WAKE_LOCK_SUSPEND, + PKEY_FORCECRASH_DEV_NAME); + return input_register_handler(&powerkey_input_handler); +} + +static void __exit powerkey_forcecrash_exit(void) +{ + del_timer(&forcecrash_timer); + wake_lock_destroy(&powerkey_lock); + input_unregister_handler(&powerkey_input_handler); +} + +module_init(powerkey_forcecrash_init); +module_exit(powerkey_forcecrash_exit); + +MODULE_AUTHOR("Srinivasa Nagaraju "); +MODULE_DESCRIPTION("Force crash on power key long press of 10 secs"); +MODULE_LICENSE("GPL V2"); diff --git a/drivers/misc/qcom/qdsp6v2/audio_aac.c b/drivers/misc/qcom/qdsp6v2/audio_aac.c index 1f02576a084887da6aab54655dab6d0ab1d6087f..94d563a211ec13692e79b9825af2792c1511d9a1 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_aac.c +++ b/drivers/misc/qcom/qdsp6v2/audio_aac.c @@ -2,7 +2,7 @@ * * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2016, 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 @@ -46,9 +46,7 @@ static long audio_ioctl_shared(struct file *file, unsigned int cmd, audio->ac->session); if (audio->feedback == NON_TUNNEL_MODE) { /* Configure PCM output block */ - rc = q6asm_enc_cfg_blk_pcm(audio->ac, - audio->pcm_cfg.sample_rate, - audio->pcm_cfg.channel_count); + rc = q6asm_enc_cfg_blk_pcm(audio->ac, 0, 0); if (rc < 0) { pr_err("pcm output block config failed\n"); break; diff --git a/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c b/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c index 42b45ec7d9d9f920e1f8a8d43a4e038bd1e8cbf4..91bbba176dfdb052e0f435321c041a1a464e45ac 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c +++ b/drivers/misc/qcom/qdsp6v2/audio_multi_aac.c @@ -2,7 +2,7 @@ * * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016, 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 @@ -58,9 +58,9 @@ static long audio_ioctl_shared(struct file *file, unsigned int cmd, audio->ac->session); if (audio->feedback == NON_TUNNEL_MODE) { /* Configure PCM output block */ - rc = q6asm_enc_cfg_blk_pcm(audio->ac, - audio->pcm_cfg.sample_rate, - audio->pcm_cfg.channel_count); + rc = q6asm_enc_cfg_blk_pcm_native(audio->ac, + aac_cfg.sample_rate, + aac_cfg.ch_cfg); if (rc < 0) { pr_err("pcm output block config failed\n"); break; diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c index 7fa5e326fa0b42805933b48bdef6621afcbd0957..b292ea70fb40d6f8fe2fdb354c010af346c38ed7 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c @@ -1062,8 +1062,6 @@ static int audio_aio_async_write(struct q6audio_aio *audio, struct audio_client *ac; struct audio_aio_write_param param; - memset(¶m, 0, sizeof(param)); - if (!audio || !buf_node) { pr_err("%s NULL pointer audio=[0x%pK], buf_node=[0x%pK]\n", __func__, audio, buf_node); diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index cf897947fff2ed2aa56745917c062f3229d38fbd..cc02144359b058e61c815c5a6439f1d5fbac2357 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -11,6 +11,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__ @@ -281,7 +286,6 @@ struct qseecom_control { wait_queue_head_t app_block_wq; atomic_t qseecom_state; int is_apps_region_protected; - bool smcinvoke_support; }; struct qseecom_sec_buf_fd_info { @@ -579,12 +583,10 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[1] = req_64bit->sb_ptr; desc.args[2] = req_64bit->sb_len; } - qseecom.smcinvoke_support = true; smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); ret = scm_call2(smc_id, &desc); if (ret) { - qseecom.smcinvoke_support = false; smc_id = TZ_OS_REGISTER_LISTENER_ID; __qseecom_reentrancy_check_if_no_app_blocked( smc_id); @@ -1009,14 +1011,10 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, struct qseecom_continue_blocked_request_ireq *req = (struct qseecom_continue_blocked_request_ireq *) req_buf; - if (qseecom.smcinvoke_support) - smc_id = - TZ_OS_CONTINUE_BLOCKED_REQUEST_SMCINVOKE_ID; - else - smc_id = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID; + smc_id = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID; desc.arginfo = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID; - desc.args[0] = req->app_or_session_id; + desc.args[0] = req->app_id; ret = scm_call2(smc_id, &desc); break; } @@ -1846,7 +1844,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, return ret; } -static int __qseecom_process_blocked_on_listener_legacy( +int __qseecom_process_reentrancy_blocked_on_listener( struct qseecom_command_scm_resp *resp, struct qseecom_registered_app_list *ptr_app, struct qseecom_dev_handle *data) @@ -1855,8 +1853,9 @@ static int __qseecom_process_blocked_on_listener_legacy( int ret = 0; struct qseecom_continue_blocked_request_ireq ireq; struct qseecom_command_scm_resp continue_resp; - bool found_app = false; + sigset_t new_sigset, old_sigset; unsigned long flags; + bool found_app = false; if (!resp || !data) { pr_err("invalid resp or data pointer\n"); @@ -1896,30 +1895,32 @@ static int __qseecom_process_blocked_on_listener_legacy( pr_debug("lsntr %d in_use = %d\n", resp->data, list_ptr->listener_in_use); ptr_app->blocked_on_listener_id = resp->data; - /* sleep until listener is available */ - qseecom.app_block_ref_cnt++; - ptr_app->app_blocked = true; - mutex_unlock(&app_access_lock); - if (wait_event_freezable( - list_ptr->listener_block_app_wq, - !list_ptr->listener_in_use)) { - pr_err("Interrupted: listener_id %d, app_id %d\n", - resp->data, ptr_app->app_id); - ret = -ERESTARTSYS; - goto exit; - } - mutex_lock(&app_access_lock); - ptr_app->app_blocked = false; - qseecom.app_block_ref_cnt--; - + do { + qseecom.app_block_ref_cnt++; + ptr_app->app_blocked = true; + sigfillset(&new_sigset); + sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); + mutex_unlock(&app_access_lock); + do { + if (!wait_event_freezable( + list_ptr->listener_block_app_wq, + !list_ptr->listener_in_use)) { + break; + } + } while (1); + mutex_lock(&app_access_lock); + sigprocmask(SIG_SETMASK, &old_sigset, NULL); + ptr_app->app_blocked = false; + qseecom.app_block_ref_cnt--; + } while (list_ptr->listener_in_use == true); ptr_app->blocked_on_listener_id = 0; /* notify the blocked app that listener is available */ pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n", resp->data, data->client.app_id, data->client.app_name); ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND; - ireq.app_or_session_id = data->client.app_id; + ireq.app_id = data->client.app_id; ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &ireq, sizeof(ireq), &continue_resp, sizeof(continue_resp)); @@ -1938,73 +1939,6 @@ exit: return ret; } -static int __qseecom_process_blocked_on_listener_smcinvoke( - struct qseecom_command_scm_resp *resp) -{ - struct qseecom_registered_listener_list *list_ptr; - int ret = 0; - struct qseecom_continue_blocked_request_ireq ireq; - struct qseecom_command_scm_resp continue_resp; - unsigned int session_id; - - if (!resp) { - pr_err("invalid resp pointer\n"); - ret = -EINVAL; - goto exit; - } - session_id = resp->resp_type; - list_ptr = __qseecom_find_svc(resp->data); - if (!list_ptr) { - pr_err("Invalid listener ID\n"); - ret = -ENODATA; - goto exit; - } - pr_debug("lsntr %d in_use = %d\n", - resp->data, list_ptr->listener_in_use); - /* sleep until listener is available */ - qseecom.app_block_ref_cnt++; - mutex_unlock(&app_access_lock); - if (wait_event_freezable( - list_ptr->listener_block_app_wq, - !list_ptr->listener_in_use)) { - pr_err("Interrupted: listener_id %d, session_id %d\n", - resp->data, session_id); - ret = -ERESTARTSYS; - goto exit; - } - mutex_lock(&app_access_lock); - qseecom.app_block_ref_cnt--; - - /* notify TZ that listener is available */ - pr_warn("Lsntr %d is available, unblock session(%d) in TZ\n", - resp->data, session_id); - ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND; - ireq.app_or_session_id = session_id; - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, - &ireq, sizeof(ireq), - &continue_resp, sizeof(continue_resp)); - if (ret) { - pr_err("scm_call for continue blocked req for session %d failed, ret %d\n", - session_id, ret); - goto exit; - } - resp->result = QSEOS_RESULT_INCOMPLETE; -exit: - return ret; -} - -static int __qseecom_process_reentrancy_blocked_on_listener( - struct qseecom_command_scm_resp *resp, - struct qseecom_registered_app_list *ptr_app, - struct qseecom_dev_handle *data) -{ - if (!qseecom.smcinvoke_support) - return __qseecom_process_blocked_on_listener_legacy( - resp, ptr_app, data); - else - return __qseecom_process_blocked_on_listener_smcinvoke( - resp); -} static int __qseecom_reentrancy_process_incomplete_cmd( struct qseecom_dev_handle *data, struct qseecom_command_scm_resp *resp) @@ -2601,6 +2535,11 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, goto unload_exit; } + if (!memcmp(data->client.app_name, "tzxflattest", strlen("tzxflattest"))) { + pr_debug("Do not unload tzxflattest app from tz\n"); + goto unload_exit; + } + __qseecom_cleanup_app(data); __qseecom_reentrancy_check_if_no_app_blocked(TZ_OS_APP_SHUTDOWN_ID); @@ -4770,15 +4709,18 @@ int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc) } resp.result = desc->ret[0]; /*req_cmd*/ - resp.resp_type = desc->ret[1]; /*incomplete:unused;blocked:session_id*/ + resp.resp_type = desc->ret[1]; /*app_id*/ resp.data = desc->ret[2]; /*listener_id*/ + dummy_private_data.client.app_id = desc->ret[1]; + dummy_app_entry.app_id = desc->ret[1]; + mutex_lock(&app_access_lock); ret = __qseecom_process_reentrancy(&resp, &dummy_app_entry, &dummy_private_data); mutex_unlock(&app_access_lock); if (ret) - pr_err("Failed on cmd %d for lsnr %d session %d, ret = %d\n", + pr_err("Failed to req cmd %d lsnr %d on app %d, ret = %d\n", (int)desc->ret[0], (int)desc->ret[2], (int)desc->ret[1], ret); desc->ret[0] = resp.result; @@ -8434,10 +8376,9 @@ out: */ static int qseecom_check_whitelist_feature(void) { - u64 version = 0; - int ret = scm_get_feat_version(FEATURE_ID_WHITELIST, &version); + int version = scm_get_feat_version(FEATURE_ID_WHITELIST); - return (ret == 0) && (version >= MAKE_WHITELIST_VERSION(1, 0, 0)); + return version >= MAKE_WHITELIST_VERSION(1, 0, 0); } static int qseecom_probe(struct platform_device *pdev) @@ -8531,11 +8472,7 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.ion_clnt = msm_ion_client_create("qseecom-kernel"); if (IS_ERR_OR_NULL(qseecom.ion_clnt)) { pr_err("Ion client cannot be created\n"); - - if (qseecom.ion_clnt != ERR_PTR(-EPROBE_DEFER)) - rc = -ENOMEM; - else - rc = -EPROBE_DEFER; + rc = -ENOMEM; goto exit_del_cdev; } diff --git a/drivers/misc/ramdump_mem_desc.c b/drivers/misc/ramdump_mem_desc.c new file mode 100644 index 0000000000000000000000000000000000000000..95fb81889df99db3446bc45a3d69f1fc2e1ac356 --- /dev/null +++ b/drivers/misc/ramdump_mem_desc.c @@ -0,0 +1,515 @@ +/* + * Author: Nandhakumar Rangasamy + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_HAVE_MEMBLOCK +#include +#endif + +static struct device *dev; +static void *mem_desc_base; +static size_t mem_desc_size; +static char *mem_desc_buf; +static unsigned int mem_desc_data_size; + +static DEFINE_MUTEX(mem_desc_lock); + +/*Random number*/ +#define RDTAGS_MEM_DESC_SIG 0x42972468 +#define DUMP_TABLE_OFFSET 0x5014 +#define MEM_DESC_MAX 64 +#define MEM_DESC_MASK 0xf + +struct mem_desc_hdr { + u32 sig; + u32 version; + u32 num_desc; + u32 reserved; +}; + +struct ramdump_mem_desc { + struct mem_desc_hdr hdr; + struct mem_desc desc[MEM_DESC_MAX]; +}; + +#define MEM_DESC_FORMAT_SIZE 114 +#define MEM_DESC_FORMAT "0x%016llx:0x%016llx:%s:%s:0x%08x\n" + +static int match_dev_by_volname(struct device *pdev, const void *data) +{ + char *volname = "cache"; + struct hd_struct *part = dev_to_part(pdev); + + if (!part->info) + goto no_match; + + if (strncmp(volname, part->info->volname, + sizeof(part->info->volname))) + goto no_match; + + return 1; +no_match: + return 0; +} + +static int get_ramdump_partition_index(void) +{ + struct device *pdev = NULL; + u8 uuid[16] = {0}; + int ret = -1; + + pdev = class_find_device(&block_class, NULL, &uuid, + match_dev_by_volname); + if (!pdev) { + dev_info(dev, "Partition device not found"); + return ret; + } + + return dev_to_part(pdev)->partno; +} + +static u32 mem_desc_update_flags(u64 start, u64 end, + struct ramdump_mem_desc *m_desc) +{ + int i, ret; + u32 flags; + + ret = get_ramdump_partition_index(); + if (ret < 0) + return 0; + + flags = ret << 9; + for (i = 0; i < m_desc->hdr.num_desc; i++) { + if (start >= m_desc->desc[i].phys_addr && + (end <= (m_desc->desc[i].phys_addr + + m_desc->desc[i].size))) + flags |= m_desc->desc[i].flags; + } + + return flags; +} + +static void mem_desc_split_sect_format( + u64 sort_buffer[], + unsigned int sort_count, + struct ramdump_mem_desc *m_desc) +{ + unsigned int i, j; + + for (j = 0; j < sort_count; j++) { + u32 flags = 0; u64 size = 0; + char *p_name = NULL, *c_name = NULL; + + if ((j+1) < sort_count) { + if (sort_buffer[j] == sort_buffer[j+1]) + continue; + } + + for (i = 0; i < m_desc->hdr.num_desc; i++) { + if (sort_buffer[j] >= m_desc->desc[i].phys_addr && + (sort_buffer[j] < (m_desc->desc[i].phys_addr + + m_desc->desc[i].size))) { + + size = sort_buffer[j + 1] - sort_buffer[j]; + flags = mem_desc_update_flags(sort_buffer[j], + sort_buffer[j+1], + m_desc); + + switch (m_desc->desc[i].flags & MEM_DESC_MASK) { + case MEM_DESC_PLATFORM: + if (p_name == NULL) + p_name = m_desc->desc[i].name; + else if ((!strncmp(p_name, + m_desc->desc[i].name, + sizeof(m_desc->desc[i].name))) + && + (m_desc->desc[i].flags >> 31)) + continue; + else { + mem_desc_data_size += snprintf( + (mem_desc_buf + + mem_desc_data_size), + MEM_DESC_FORMAT_SIZE, + MEM_DESC_FORMAT, + sort_buffer[j], + size, + m_desc->desc[i].name, + "NULL", + flags); + } + break; + case MEM_DESC_CORE: + c_name = m_desc->desc[i].name; + break; + } + } + } + if (p_name != NULL) { + mem_desc_data_size += snprintf( + (mem_desc_buf + + mem_desc_data_size), + MEM_DESC_FORMAT_SIZE, + MEM_DESC_FORMAT, + sort_buffer[j], + size, + p_name, + c_name ? c_name : "NULL", + flags); + } + } +} + +void ramdump_add_mem_desc(struct mem_desc *desc) +{ + struct ramdump_mem_desc *m_desc = NULL; + unsigned int offset; + + if (!mem_desc_base) { + dev_info(dev, "Adding mem_desc failed\n"); + return; + } + + mutex_lock(&mem_desc_lock); + m_desc = (struct ramdump_mem_desc *)mem_desc_base; + offset = sizeof(struct mem_desc_hdr) + + m_desc->hdr.num_desc * sizeof(struct mem_desc); + + if (m_desc->hdr.num_desc >= MEM_DESC_MAX) + goto exit; + + if ((offset + sizeof(struct mem_desc)) > mem_desc_size) + goto exit; + + memcpy_toio( + ((struct ramdump_mem_desc *)(((unsigned long)m_desc) + offset)), + desc, sizeof(struct mem_desc)); + + m_desc->hdr.num_desc++; +exit: + mutex_unlock(&mem_desc_lock); +} +EXPORT_SYMBOL(ramdump_add_mem_desc); + +void ramdump_remove_mem_desc(struct mem_desc *desc) +{ + struct ramdump_mem_desc *m_desc = NULL; + struct ramdump_mem_desc *m_desc_buf = NULL; + unsigned int i, offset, m_desc_size; + + if (!mem_desc_base) { + dev_info(dev, "Removing mem_desc failed\n"); + return; + } + + mutex_lock(&mem_desc_lock); + m_desc = (struct ramdump_mem_desc *)mem_desc_base; + m_desc_size = sizeof(struct mem_desc_hdr) + + m_desc->hdr.num_desc * sizeof(struct mem_desc); + + m_desc_buf = vmalloc(m_desc_size); + if (!m_desc_buf) { + dev_err(dev, "Failed to allocate mem_desc buffer\n"); + goto exit; + } + + memcpy_fromio(m_desc_buf, mem_desc_base, m_desc_size); + offset = sizeof(struct mem_desc_hdr) + + m_desc_buf->hdr.num_desc * sizeof(struct mem_desc); + + for (i = 0; i < m_desc_buf->hdr.num_desc; i++) { + if ((desc->phys_addr == m_desc_buf->desc[i].phys_addr) && + !strncmp(desc->name, m_desc_buf->desc[i].name, + sizeof(m_desc_buf->desc[i].name))) { + memset(&m_desc_buf->desc[i], 0, + sizeof(struct mem_desc)); + memmove(&m_desc_buf->desc[i], + &m_desc_buf->desc[i + 1], + (m_desc_buf->hdr.num_desc - i - 1) + * sizeof(struct mem_desc)); + m_desc_buf->hdr.num_desc--; + } + } + + memset_io(m_desc, 0, m_desc_size); + memcpy_toio(m_desc, m_desc_buf, m_desc_size); + vfree(m_desc_buf); +exit: + mutex_unlock(&mem_desc_lock); +} +EXPORT_SYMBOL(ramdump_remove_mem_desc); + +static int cmp_sort_addr(const void *a, const void *b) +{ + u64 x = *(u64 *)a; + u64 y = *(u64 *)b; + int ret = 0; + + if (x < y) + ret = -1; + if (x > y) + ret = 1; + + return ret; +} + +static void get_mem_desc(void) +{ + unsigned int count = 0; + struct ramdump_mem_desc *m_desc = + (struct ramdump_mem_desc *)mem_desc_base; + unsigned int i, num_desc; + + num_desc = (m_desc->hdr.num_desc < MEM_DESC_MAX) ? + m_desc->hdr.num_desc : MEM_DESC_MAX; + + if (m_desc->hdr.sig == RDTAGS_MEM_DESC_SIG) { + u64 sort_buffer[MEM_DESC_MAX << 1]; + for (i = 0; i < num_desc; i++) { + u64 start, end; + start = m_desc->desc[i].phys_addr; + end = m_desc->desc[i].phys_addr + m_desc->desc[i].size; + + memcpy(&sort_buffer[count++], &start, + sizeof(u64)); + memcpy(&sort_buffer[count++], &end, + sizeof(u64)); + } + + sort(sort_buffer, count, sizeof(u64), + cmp_sort_addr, NULL); + mem_desc_split_sect_format(sort_buffer, count, m_desc); + } +} + +#ifdef CONFIG_HAVE_MEMBLOCK +static void add_memblock_info(void) +{ + int i; + struct memblock_type *block = &memblock.memory; + + for (i = 0; i < block->cnt; i++) { + struct mem_desc desc; + + desc.phys_addr = (u64)block->regions[i].base; + desc.size = (u64)block->regions[i].size; + desc.flags = MEM_DESC_CORE; + strlcpy(desc.name, "vmcore", sizeof(desc.name)); + ramdump_add_mem_desc(&desc); + } +} +#else +static void add_ioresource(struct resource *res, + char *iores_name, + char *core_name) +{ + while (res != NULL) { + if (res->child != NULL) + add_ioresource(res->child, iores_name, core_name); + + if ((res->flags & IORESOURCE_MEM) && + strcmp(res->name, iores_name) == 0) { + if (core_name != NULL) { + struct mem_desc desc; + + desc.phys_addr = (u64)res->start; + desc.size = + ((u64)res->end - (u64)res->start) + 1; + desc.flags = MEM_DESC_CORE; + strlcpy(desc.name, core_name, + sizeof(desc.name)); + ramdump_add_mem_desc(&desc); + } + } + res = res->sibling; + } +} +#endif + +static void mem_desc_add_linux_meminfo(void) +{ +#ifdef CONFIG_HAVE_MEMBLOCK + add_memblock_info(); +#else + add_ioresource(&iomem_resource, "System RAM", "vmcore"); +#endif +} + +static ssize_t mem_desc_read(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + loff_t pos = *offset; + ssize_t count; + + if (pos == 0) + get_mem_desc(); + + if (pos >= mem_desc_data_size) { + memset_io(mem_desc_base, 0x0, mem_desc_data_size); + return 0; + } + + count = min(len, (size_t)(mem_desc_data_size - pos)); + if (copy_to_user(buf, mem_desc_buf + pos, count)) + return -EFAULT; + + *offset += count; + return count; +} + +static const struct file_operations mem_desc_file_ops = { + .owner = THIS_MODULE, + .read = mem_desc_read, +}; + +#define MAX_DESC_PER_TYPE 32 +static int mem_desc_init(void) +{ + int ret = 0; + struct proc_dir_entry *subentry_mem_desc; + + mem_desc_buf = kmalloc((MEM_DESC_FORMAT_SIZE * 3 * MAX_DESC_PER_TYPE), + GFP_KERNEL); + if (mem_desc_buf == NULL) { + dev_err(dev, "Failed to allocte memory regs_buf\n"); + ret = -ENOMEM; + goto exit; + } + + subentry_mem_desc = proc_create_data("mem_desc", + S_IFREG | S_IRUGO, NULL, + &mem_desc_file_ops, NULL); + if (!subentry_mem_desc) { + dev_err(dev, "Failed to create proc subentry mem_desc\n"); + ret = -1; + goto exit1; + } + + return ret; + +exit1: + kfree(mem_desc_buf); + mem_desc_buf = NULL; +exit: + return ret; +} + +static int is_ramdump_mode(void) +{ + return *((int *)(dev->platform_data)); +} + +static int mem_desc_driver_probe(struct platform_device *pdev) +{ + struct resource *res_mem_desc; + struct ramdump_mem_desc *m_desc; + void *mem_desc_end; + int ret = 0; + + dev = &pdev->dev; + + res_mem_desc = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "ramdump_memdesc"); + if (!res_mem_desc || !res_mem_desc->start) { + dev_err(dev, + "Ramdump tags driver mem desc resource" + " invalid/absent\n"); + ret = -ENODEV; + goto exit; + } + + mem_desc_size = res_mem_desc->end + - res_mem_desc->start + 1; + mem_desc_base = (void *)ioremap(res_mem_desc->start, + mem_desc_size); + if (!mem_desc_base) { + dev_err(dev, "Failed to mem desc map %ld bytes at 0x%08llx\n", + mem_desc_size, res_mem_desc->start); + ret = -EINVAL; + goto exit; + } + + mem_desc_end = mem_desc_base + mem_desc_size; + dev_info(dev, "res_mem_desc_base = 0x%08llx mem_desc size = %ld\n", + res_mem_desc->start, mem_desc_size); + m_desc = (struct ramdump_mem_desc *)mem_desc_base; + + dev_info(dev, "ramdump_mode = %s\n", + is_ramdump_mode() ? "ramdump" : "normal"); + + if (!is_ramdump_mode()) { + memset_io(mem_desc_base, 0x0, mem_desc_size); + m_desc->hdr.sig = RDTAGS_MEM_DESC_SIG; + mem_desc_add_linux_meminfo(); + } else { + if (m_desc->hdr.sig == RDTAGS_MEM_DESC_SIG) { + dev_info(dev, "Found memory descriptors\n"); + if (mem_desc_init() != 0) + goto exit; + } else { + dev_info(dev, "NO valid memory descriptors found!!\n"); + ret = -EINVAL; + goto exit; + } + } + + return 0; +exit: + if (mem_desc_base) { + iounmap(mem_desc_base); + mem_desc_base = NULL; + } + + return ret; +} + +static struct platform_driver mem_desc_driver = { + .probe = mem_desc_driver_probe, + .driver = { + .name = "ramdump_memdesc", + }, +}; + +static int __init mem_desc_core_init(void) +{ + return platform_driver_register(&mem_desc_driver); +} + +static void __exit mem_desc_module_exit(void) +{ + if (mem_desc_base) { + iounmap(mem_desc_base); + mem_desc_base = NULL; + } + + platform_driver_unregister(&mem_desc_driver); +} + +core_initcall(mem_desc_core_init); +module_exit(mem_desc_module_exit); diff --git a/drivers/misc/rdtags.c b/drivers/misc/rdtags.c new file mode 100644 index 0000000000000000000000000000000000000000..0c40b2ff6c64cf5a3b411da2d18a49b521700e7a --- /dev/null +++ b/drivers/misc/rdtags.c @@ -0,0 +1,1176 @@ +/* + * + * Author: Nilsson, Stefan 2 + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RDTAGS_SIG 0x47415452 +#define RDTAGS_NAME_SIZE 28 +#define RDTAGS_ALIGNMENT 64 + +#define RDTAGS_PROC_NODE_NAME "rdtag" +#define RDTAGS_PROC_DIR_NAME "rdtags" +#define LAST_RDTAGS_PROC_DIR_NAME "last_rdtags" + +static struct device *dev; +static struct proc_dir_entry *entry; +static void *rdtags_io_base; +static void *rdtags_base; +static void *rdtags_end; +static void *last_rdtags_base; +static void *last_rdtags_end; +static struct proc_dir_entry *last_entry; +static size_t rdtags_size; +static DEFINE_MUTEX(rdlock); +static uint8_t rdtags_initialized; + +struct rtag_head { + uint32_t sig; + uint32_t data_size; + uint8_t name[RDTAGS_NAME_SIZE]; + uint8_t null_term; /* Shall be 0 to preserve compatibility */ + uint8_t flags; + uint16_t crc; + uint8_t data[0]; +}; + +enum procfs_cmd { + PROCFS_CMD_ADD, + PROCFS_CMD_DELETE, +}; + +struct procfs_fifo_item { + enum procfs_cmd cmd; + char name[RDTAGS_NAME_SIZE]; +}; + +#define PROCFS_FIFO_SIZE 64 +static DEFINE_KFIFO(procfs_fifo, struct procfs_fifo_item, PROCFS_FIFO_SIZE); + +static void procfs_work_func(struct work_struct *work); +static DECLARE_WORK(procfs_work, procfs_work_func); + +#define PROCFS_ASYNC_ADD(x) procfs_async_cmd((x), PROCFS_CMD_ADD) +#define PROCFS_ASYNC_DELETE(x) procfs_async_cmd((x), PROCFS_CMD_DELETE) + +#define SLEEP_TIME_ASYNC_FINISH 10 /* ms */ + +#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) +#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) + +#define RDTAGS_NEXT_TAG(x) ((struct rtag_head *) \ + ALIGN((unsigned long)x + x->data_size + \ + sizeof(*x), RDTAGS_ALIGNMENT)) + +#define RDTAGS_BLK_SIZE(x) ALIGN(x->data_size + sizeof(*x), RDTAGS_ALIGNMENT) +#define RDTAGS_BASE_VALID(x) ((void *)x >= rdtags_base && \ + (void *)x < rdtags_end) +#define LAST_RDTAGS_BASE_VALID(x) ((void *)x >= last_rdtags_base && \ + (void *)x < last_rdtags_end) + +#define RDTAGS_ADDR_VALID(x) (RDTAGS_BASE_VALID(x) || LAST_RDTAGS_BASE_VALID(x)) + +#define CRC_SIZE 2 /* bytes */ +#define RDTAG_FLAGS_CRC_PRESENT 0x1 + +static ssize_t tag_read(struct file *file, char __user *buf, size_t size, + loff_t *off); + +static const struct file_operations tag_fops = { + .read = tag_read, +}; + +static int procfs_create_node(char *name) +{ + struct proc_dir_entry *subentry; + + if (!entry) + return -ENXIO; + + subentry = proc_create_data(name, S_IFREG | S_IRUSR, entry, &tag_fops, + (void *)name); + if (!subentry) + return -ENOMEM; + + + return 0; +} + +static int procfs_delete_node(char *name) +{ + if (!entry) + return -ENXIO; + + remove_proc_entry(name, entry); + + return 0; +} + +static void procfs_work_func(struct work_struct *work) +{ + struct procfs_fifo_item item; + + while (kfifo_get(&procfs_fifo, &item)) { + int ret; + char *name = (char *)&item.name; + + dev_dbg(dev, "wq: Processing request %s %s\n", + item.cmd == PROCFS_CMD_ADD ? "ADD" : "DELETE", name); + + switch (item.cmd) { + case PROCFS_CMD_ADD: + ret = procfs_create_node(name); + if (ret < 0) + dev_err(dev, "wq: Failed to create proc" \ + "subentry \"%s\": %d\n", name, ret); + break; + case PROCFS_CMD_DELETE: + ret = procfs_delete_node(name); + if (ret < 0) + dev_err(dev, "wq: Failed to remove proc" \ + "subentry \"%s\": %d\n", name, ret); + break; + default: + dev_err(dev, "wq: Unknown request: %d for %s\n", + item.cmd, name); + } + } +} + +static void procfs_async_cmd(char *name, enum procfs_cmd cmd) +{ + struct procfs_fifo_item item; + + if (unlikely(kfifo_is_full(&procfs_fifo))) { + dev_err(dev, "procfs FIFO buffer overflow! procfs will" \ + "be out of sync!\n"); + return; + } + item.cmd = cmd; + strlcpy(item.name, name, RDTAGS_NAME_SIZE); + dev_dbg(dev, "procfs WQ request: %s %s\n", + cmd == PROCFS_CMD_ADD ? "ADD" : "DELETE", name); + kfifo_put(&procfs_fifo, item); + schedule_work(&procfs_work); +} + +static void rdtags_flush(void) +{ + if (rdtags_io_base && rdtags_base) + memcpy_toio(rdtags_io_base, rdtags_base, rdtags_size); +} + +/* + * Calculates the CRC for a RDTAG. Both headers and data is covered by the CRC. + * + * mt: Pointer to a valid (size checked) RDTAG + * + * Returns: The calculated CRC + */ +static uint16_t calc_crc(struct rtag_head *mt) +{ + uint16_t crc; + + /* Calculate CRC of header (minus crc field) */ + crc = crc16(0, (char *)mt, sizeof(struct rtag_head) - CRC_SIZE); + + /* Update the crc with the data part */ + crc = crc16(crc, mt->data, mt->data_size); + + return crc; +} + +/* + * Updates a RDTAG with a correct CRC + * + * mt: Pointer to a RDTAG + * + */ +static void update_crc(struct rtag_head *mt) +{ + /* First do some basic sanity checking */ + void *tag_end = (void *)(((unsigned long)mt) + sizeof(*mt) + + mt->data_size); + if (!RDTAGS_BASE_VALID(mt) || + !RDTAGS_BASE_VALID((tag_end)) || + (mt->data_size > rdtags_size)) { + /* Unable to calculate CRC */ + return; + } + + /* Update the rdtag with correct CRC value */ + mt->null_term = 0; + mt->flags = RDTAG_FLAGS_CRC_PRESENT; + + /* Calculate the crc */ + mt->crc = calc_crc(mt); +} + +/* + * Verifies the CRC of a tag + * + * mt: Pointer to a RDTAG + * + * Returns 1 on successful CRC verification + * Returns 0 if CRC field is missing (earlier version of RDTAGS) + * Returns -EILSEQ if CRC is present and verfication fails, or an unexpected + * error is encountered. + */ +static int verify_crc(struct rtag_head *mt) +{ + uint16_t crc; + uint16_t rdtag_crc; + + /* First do some basic sanity checking */ + void *tag_end = (void *)(((unsigned long)mt) + sizeof(*mt) + + mt->data_size); + if (!RDTAGS_ADDR_VALID(mt) || + !RDTAGS_ADDR_VALID((tag_end)) || + (mt->data_size > rdtags_size)) { + dev_err(dev, "Tag fails basic sanity check, " \ + "clearing rest of rdtags area!\n"); + goto error; + } + + /* Get CRC from tag */ + rdtag_crc = mt->flags & RDTAG_FLAGS_CRC_PRESENT ? mt->crc : 0; + if (rdtag_crc == 0) { + /* No CRC present, probably an older version of rdtags */ + return 0; + } + + /* Calculate expected CRC and compare */ + crc = calc_crc(mt); + if (crc == rdtag_crc) + return 1; + + dev_err(dev, "Tag fails CRC check, suspected memory corruption, " \ + "clearing rest of rdtags area!\n"); +error: + if (LAST_RDTAGS_BASE_VALID(mt)) { + memset(mt, 0x0, last_rdtags_end - (void *)mt); + } + + if (RDTAGS_BASE_VALID(mt)) { + memset(mt, 0x0, rdtags_end - (void *)mt); + rdtags_flush(); + } + + return -EILSEQ; +} + +static char *get_valid_name(char *name) +{ + char *temp; + + if (!name) + return NULL; + + /* Make sure the name is not longer than RDTAGS_NAME_SIZE */ + if (RDTAGS_NAME_SIZE == strnlen(name, RDTAGS_NAME_SIZE)) + name[RDTAGS_NAME_SIZE - 1] = 0x0; + + /* Check the name for disallowed characters */ + temp = strpbrk(name, "\r\n /"); + if (temp) + *temp = 0x0; + + /* Check that the name still actually contains something */ + if (name[0] == 0x0) + return NULL; + + return name; +} + +static struct rtag_head *get_next_free(void) +{ + struct rtag_head *mt = (struct rtag_head *)rdtags_base; + + while (mt->sig == RDTAGS_SIG) { + + /* Verify CRC of tag, if fail, it can be overwritten */ + if (verify_crc(mt) < 0) + return mt; + + /* Go to next tag */ + mt = RDTAGS_NEXT_TAG(mt); + + /* Check that we are not outside the buffer */ + if (!RDTAGS_BASE_VALID(mt)) + return NULL; + } + + return mt; +} + +static struct rtag_head *get_tag(const char *name) +{ + struct rtag_head *mt = (struct rtag_head *)rdtags_base; + + while (mt->sig == RDTAGS_SIG) { + + /* Verify CRC of tag */ + if (verify_crc(mt) < 0) + return NULL; + + if (strncmp(name, mt->name, RDTAGS_NAME_SIZE) == 0) + return mt; + + /* Go to next tag */ + mt = RDTAGS_NEXT_TAG(mt); + + /* Check that we are not outside the buffer */ + if (!RDTAGS_BASE_VALID(mt)) + return NULL; + } + + return NULL; +} + +static void _remove_tag(struct rtag_head *mt) +{ + struct rtag_head *mt_next, *mt_free; + size_t size_mv, size_clr; + + if (!RDTAGS_BASE_VALID(mt)) + return; + /* + * we need to get some address & size for recompacting tags: + * |- size_mv -| + * -------------------------------------------------------------- + * |rdtags_base|...| mt |mt_next|...|mt_free|...|rdtags_end| + * -------------------------------------------------------------- + * |-size_clr-| + */ + mt_next = RDTAGS_NEXT_TAG(mt); + if (!RDTAGS_BASE_VALID(mt_next)) + mt_next = (struct rtag_head *)rdtags_end; + + mt_free = get_next_free(); + if (NULL == mt_free) + mt_free = (struct rtag_head *)rdtags_end; + size_mv = ((unsigned long)mt_free) - ((unsigned long)mt_next); + size_clr = RDTAGS_BLK_SIZE(mt); + + /* Remove procfs interface asynchronously */ + PROCFS_ASYNC_DELETE(mt->name); + + /* move rear tags */ + memmove((void *)mt, (void *)mt_next, size_mv); + + /* clear vacated memory */ + if ((size_clr <= rdtags_size) && + ((void *)(unsigned long)mt_free - size_clr) >= rdtags_base) { + memset((void *)(((unsigned long)mt_free) - size_clr), 0, + size_clr); + } + + rdtags_flush(); +} + +/* + * Removes a tag + * + * name: Name of tag to remove + * + * Returns 0 on success or a negative error code on failure + */ +int rdtags_remove_tag(const char *name) +{ + struct rtag_head *mt; + int ret = 0; + + if (!name) + return -EINVAL; + + if (!rdtags_initialized) + return -ENODEV; + + dev_dbg(dev, "Removing tag \"%s\"\n", name); + + mutex_lock(&rdlock); + + /* Get the tag */ + mt = get_tag(name); + if (!mt) { + ret = -ENOENT; + goto exit; + } + + _remove_tag(mt); + +exit: + mutex_unlock(&rdlock); + + if (ret) + dev_err(dev, "Could not remove tag \"%s\"\n", name); + else + dev_dbg(dev, "Removed tag \"%s\"\n", name); + + return ret; +} +EXPORT_SYMBOL(rdtags_remove_tag); + +static int _add_tag(const char *name, const unsigned char *data, size_t size) +{ + struct rtag_head *mt = get_next_free(); + void *tag_end = (void *)(((unsigned long)mt) + sizeof(*mt) + size); + + if (!mt || (tag_end > rdtags_end)) { + /* We have run out of tag space */ + dev_err(dev, "Out of tag space! Could not add tag \"%s\" " \ + "with %zd bytes of data!\n", name, size); + return -ENOMEM; + } + + mt->sig = RDTAGS_SIG; + strlcpy(mt->name, name, RDTAGS_NAME_SIZE); + memcpy(mt->data, data, size); + mt->data_size = size; + update_crc(mt); + + /* Add procfs interface asynchronously */ + PROCFS_ASYNC_ADD(mt->name); + + rdtags_flush(); + + return 0; +} + +static int _update_tag(struct rtag_head *mt, const unsigned char *data, + size_t size) +{ + char name[RDTAGS_NAME_SIZE]; + struct rtag_head *mt_free; + size_t free_size; + + if (!mt || mt->sig != RDTAGS_SIG) { + dev_err(dev, "Not a valid RTAG!\n"); + return -ENOENT; + } + + /* If the size is identical, we can update the previous tag */ + if (size == mt->data_size) { + dev_dbg(dev, "Updating tag \"%s\"\n", mt->name); + memcpy(mt->data, data, size); + update_crc(mt); + return 0; + } + + /* compute available memory size if recompact tags */ + free_size = RDTAGS_BLK_SIZE(mt); + mt_free = get_next_free(); + if (NULL == mt_free) + mt_free = (struct rtag_head *)rdtags_end; + free_size += ((unsigned long)rdtags_end) - ((unsigned long)mt_free); + + /* make sure the new tag fits before removing the old one */ + if (free_size < size + sizeof(*mt)) { + dev_err(dev, "No enough memory, abort updating tag \"%s\"\n", + mt->name); + return -ENOMEM; + } else { + dev_dbg(dev, "Rewriting tag \"%s\"\n", mt->name); + strlcpy(name, mt->name, RDTAGS_NAME_SIZE); + _remove_tag(mt); + + return _add_tag(name, data, size); + } +} + +/* + * append data onto tag + * + * Note that if the tag name already exists, the existing tag + * will be updated (names must be unique). + * + * name: Name of tag to add + * data: Pointer to the data to add + * size: Size of the data to add + * + * Returns 0 on success or a negative error code on failure + */ +int rdtags_append_tagdata(const char *name, const unsigned char *data, + const uint32_t size) +{ + struct rtag_head *mt; + int ret = 0; + + if (!name || !data || size == 0) + return -EINVAL; + + if (!rdtags_initialized) + return -ENODEV; + + dev_dbg(dev, "Appending tag \"%s\"\n", name); + + mutex_lock(&rdlock); + + /* First check if the tag exists */ + mt = get_tag(name); + if (mt != NULL) { + char *kbuf; + unsigned int totalsize = 0; + + totalsize = size + mt->data_size; + + kbuf = vmalloc(totalsize); + if (NULL == kbuf) { + dev_err(dev, "Unable to assign memory.\n"); + ret = -ENOMEM; + goto exit; + } + + /* Update the tag */ + memcpy(kbuf, mt->data, mt->data_size); + memcpy((kbuf + mt->data_size), data, size); + ret = _update_tag(mt, kbuf, totalsize); + vfree(kbuf); + goto exit; + } + + /* Add the tag */ + ret = _add_tag(name, data, size); +exit: + mutex_unlock(&rdlock); + if (ret) + dev_err(dev, "Could not add/update tag \"%s\" with %d bytes of data\n\n", + name, size); + else + dev_dbg(dev, "Added/updated tag \"%s\" with %d bytes of data\n\n", + name, size); + + return ret; +} +EXPORT_SYMBOL(rdtags_append_tagdata); + +/* + * Adds a tag + * + * Note that if the tag name already exists, the existing tag + * will be updated (names must be unique). + * + * name: Name of tag to add + * data: Pointer to the data to add + * size: Size of the data to add + * + * Returns 0 on success or a negative error code on failure + */ +int rdtags_add_tag(const char *name, const unsigned char *data, + const size_t size) +{ + struct rtag_head *mt; + int ret = 0; + + if (!name || !data || size == 0) + return -EINVAL; + + if (!rdtags_initialized) + return -ENODEV; + + dev_dbg(dev, "Adding tag \"%s\"\n", name); + + mutex_lock(&rdlock); + + /* First check if the tag exists */ + mt = get_tag(name); + + if (mt != NULL) { + /* Update the tag */ + ret = _update_tag(mt, data, size); + goto exit; + } + + /* Add the tag */ + ret = _add_tag(name, data, size); +exit: + mutex_unlock(&rdlock); + + if (ret) + dev_err(dev, "Could not add/update tag \"%s\" with %zd" \ + "bytes of data\n\n", name, size); + else + dev_dbg(dev, "Added/updated tag \"%s\" with %zd" \ + "bytes of data\n\n", name, size); + + return ret; +} +EXPORT_SYMBOL(rdtags_add_tag); + +/* + * Gets the data from a tag + * + * name: Name of tag to get data from + * data: Pointer to the buffer to receive the data + * size: Size of the buffer to receive the data. Will be updated with the + * actual size of the data. + * + * Returns a negative error code or 0 on success + */ +int rdtags_get_tag_data(const char *name, unsigned char *data, size_t *size) +{ + struct rtag_head *mt; + int ret = 0; + + if (!name || !size) + return -EINVAL; + + if (!rdtags_initialized) + return -ENODEV; + + mutex_lock(&rdlock); + + /* First check if the tag exists */ + mt = get_tag(name); + + if (mt == NULL) { + ret = -ENOENT; + goto error; + } + + /* Check if the buffer is valid and that it is large enough */ + if (!data || (*size < mt->data_size)) { + /* Update "size" with the required size */ + *size = mt->data_size; + ret = -ENOBUFS; + goto error; + } + + /* Copy the data and update the size */ + memcpy(data, mt->data, mt->data_size); + *size = mt->data_size; +error: + mutex_unlock(&rdlock); + if (ret == -ENOBUFS) + dev_dbg(dev, "Returning size %zd for tag \"%s\"!\n", + *size, name); + else if (ret) + dev_err(dev, "Could not get data for tag \"%s\": %d!\n", + name, ret); + else + dev_dbg(dev, "Read data of %zd bytes for tag \"%s\"!\n", + *size, name); + + return ret; +} +EXPORT_SYMBOL(rdtags_get_tag_data); + +/* + * Clears all tags and "reformats" the entire tag area + */ +void rdtags_clear_tags(void) +{ + struct rtag_head *mt = (struct rtag_head *)rdtags_base; + + if (!rdtags_initialized) { + dev_err(dev, "Not yet initialized, cannot clear!\n"); + return; + } + + dev_dbg(dev, "Clearing rdtags!\n"); + + mutex_lock(&rdlock); + + /* Go through all tags and remove their procfs nodes */ + while (mt->sig == RDTAGS_SIG) { + /* Verify tag integrity */ + if (verify_crc(mt) < 0) + break; + + /* Remove the procfs entry for the tag */ + PROCFS_ASYNC_DELETE(mt->name); + + mt = RDTAGS_NEXT_TAG(mt); + } + + /* Finally reset the entire area to make it clean */ + memset(rdtags_base, 0x0, rdtags_size); + rdtags_flush(); + mutex_unlock(&rdlock); +} +EXPORT_SYMBOL(rdtags_clear_tags); + +static int rebuild_tag_tree(const unsigned char *buf, size_t size) +{ + struct rtag_head *mt = (struct rtag_head *)buf; + int count = 0; + + dev_dbg(dev, "Building tag tree\n"); + + while (mt && mt->sig == RDTAGS_SIG) { + /* Verify tag integrity */ + if (verify_crc(mt) < 0) + break; + + if (!get_valid_name(mt->name)) { + dev_warn(dev, "Found tag with invalid name!" \ + "Skipping it!\n"); + goto loop_next; + } + + count++; + dev_dbg(dev, " Found tag: \"%s\" - with %d bytes of data\n", + mt->name, mt->data_size); + + /* Add procfs interface synchronously */ + if (procfs_create_node(mt->name) < 0) + dev_warn(dev, "Failed to create proc subentry \"%s\"\n", + mt->name); +loop_next: + /* Go to next tag */ + mt = RDTAGS_NEXT_TAG(mt); + + /* Check that we are not outside the buffer */ + if (!RDTAGS_BASE_VALID(mt) && !LAST_RDTAGS_BASE_VALID(mt)) + break; + } + + return count; +} + +static ssize_t last_tags_read(struct file *file, char __user *ubuf, + size_t len, loff_t *offset) +{ + loff_t pos = *offset; + ssize_t count = 0; + struct rtag_head *mt = (struct rtag_head *)last_rdtags_base; + char *name = file->f_path.dentry->d_iname; + + while (mt->sig == RDTAGS_SIG) { + + if (strncmp(name, mt->name, RDTAGS_NAME_SIZE) == 0) { + if ((size_t)pos >= mt->data_size) + return 0; + count = min(len, (size_t)(mt->data_size - pos)); + if (copy_to_user(ubuf, mt->data + pos, count)) + return -EFAULT; + break; + } + + /* Go to next tag */ + mt = RDTAGS_NEXT_TAG(mt); + + /* Check that we are not outside the buffer */ + if (!LAST_RDTAGS_BASE_VALID(mt)) + return 0; + } + + *offset += count; + return count; +} + +static ssize_t tag_read (struct file *file, char __user *ubuf, size_t len, + loff_t *offset) +{ + ssize_t count; + loff_t pos = *offset; + size_t bufsize; + unsigned char *buf; + char *name = file->f_path.dentry->d_iname; + char *dir = file->f_path.dentry->d_parent ? + file->f_path.dentry->d_parent->d_iname : NULL; + int ret; + + if (!name || !dir) + return 0; + + /* check for last_rdtags list */ + if (!strncmp(dir, "last_rdtags", 11)) + return last_tags_read(file, ubuf, len, offset); + + + /* Get the size of the required data buffer */ + if (rdtags_get_tag_data(name, NULL, &bufsize) != -ENOBUFS) { + dev_err(dev, "Could not find tag \"%s\"!\n", + name ? name : "NULL"); + return 0; + } + + buf = kzalloc(bufsize, GFP_KERNEL); + if (!buf) { + dev_err(dev, "Could not allocate %zd bytes of memory!\n", + bufsize); + return 0; + } + + /* + * Fill the buffer with data. + * This assumes that the tag size has not changed since the previous + * call to rdtags_get_tag_data. If it has, this call will fail, and + * the caller has to re-read the tag. + */ + ret = rdtags_get_tag_data(name, buf, &bufsize); + if (ret) { + dev_err(dev, "Could not get %zd bytes of data for" \ + "tag \"%s\": %d!\n", bufsize, name, ret); + kfree(buf); + return 0; + } + + count = MIN(len, bufsize - pos); + if (copy_to_user(ubuf, buf + pos, count)) { + kfree(buf); + return -EFAULT; + } + + kfree(buf); + *offset += count; + return count; +} + +static ssize_t tags_read(struct file *file, char __user *ubuf, size_t len, + loff_t *offset) +{ + /* Assume that this text always fits in count bytes */ + char *message = "Usage: [tag data]\n" + "\n" + "command may be one of the following:\n" + " * clear\n" + " * append \n" + " * delete \n"; + loff_t pos = *offset; + len = strlen(message); + if (pos >= len) + return 0; + + if (copy_to_user(ubuf, message, len)) + return -EFAULT; + + *offset += len; + + return len; +} + +static ssize_t tags_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *offset) +{ + char *tag_data; + int tag_size; + void *kbuf; + char *tag_append_data; + + if (0 == count) + return 0; + + kbuf = kmalloc(count + 1, GFP_KERNEL); + if (NULL == kbuf) { + dev_err(dev, "Unable to assign memory.\n"); + return -ENOMEM; + } + + /* Copy to kernel space */ + tag_size = copy_from_user(kbuf, ubuf, count); + + /* NULL terminate is needed, since we will handle strings on kbuf */ + *((char *)(kbuf + count)) = 0x00; + + if (tag_size > 0) { + dev_err(dev, "Unable to copy %d bytes from user space!\n", + (int)tag_size); + goto exit; + } + + /* Check for special single commands */ + if (strncmp(kbuf, "clear", 5) == 0) { + rdtags_clear_tags(); + goto exit; + } + + /* Find delimiter */ + tag_data = strnchr(kbuf, RDTAGS_NAME_SIZE, ' '); + + if (!tag_data) { + dev_err(dev, "Incorrect format, please supply a string of " \ + "format: \n"); + goto exit; + } + + /* Null terminate name at delimiter and increment tag_data pointer */ + *tag_data++ = 0x0; + + /* Do some basic sanity checking */ + if (!get_valid_name(kbuf)) + goto exit; + + /* + * get tag data size. note that: + * get_valid_name(kbuf) has guaranteed that + * strlen(kbuf) < RDTAGS_NAME_SIZE + */ + tag_size = count - (strnlen(kbuf, RDTAGS_NAME_SIZE - 1) + 1); + + /* Check for special dual commands */ + if (strncmp(kbuf, "delete", RDTAGS_NAME_SIZE) == 0) { + /* Do some basic sanity checking */ + if (!get_valid_name(tag_data)) + goto exit; + + /* Remove the tag */ + rdtags_remove_tag(tag_data); + goto exit; + } + + if (strncmp(kbuf, "append", RDTAGS_NAME_SIZE) == 0) { + tag_append_data = strnchr(tag_data, RDTAGS_NAME_SIZE, ' '); + if (!tag_append_data) { + dev_err(dev, "Incorrect format to append, " \ + "please supply " \ + "a string of \n"); + goto exit; + } + + *tag_append_data = 0x0; + /* Do some basic sanity checking */ + if (!get_valid_name(tag_data)) + goto exit; + + tag_append_data++; + tag_size = strlen(tag_append_data); + /*append data on the tag */ + rdtags_append_tagdata(tag_data, tag_append_data, tag_size); + goto exit; + } + + /* Add the tag */ + if (rdtags_add_tag(kbuf, tag_data, tag_size)) + dev_err(dev, "rdtags_add_tag failed.\n"); + +exit: + kfree(kbuf); + + /* Make sure all asynchronous work is complete before returning */ + while (!kfifo_is_empty(&procfs_fifo) && work_busy(&procfs_work)) { + dev_dbg(dev, "Sleeping while waiting for WQ to finish\n"); + msleep(SLEEP_TIME_ASYNC_FINISH); + } + + return count; +} + +static const struct file_operations rdnode_fops = { + .read = tags_read, + .write = tags_write, +}; + +static int last_rdtags_init(void) +{ + struct rtag_head *mt; + int nbr_old_tags = 0; + int ret = 0; + + last_rdtags_base = (void *)__get_free_pages(GFP_KERNEL, + get_order(rdtags_size)); + if (!last_rdtags_base) { + dev_err(dev, "Failed to allocate last_rdtags buffer\n"); + goto exit; + } + + memcpy_fromio(last_rdtags_base, rdtags_io_base, rdtags_size); + last_rdtags_end = last_rdtags_base + rdtags_size; + + /* Check if the buffer contains a valid start tag */ + + mt = (struct rtag_head *)last_rdtags_base; + if (mt->sig == RDTAGS_SIG) { + + dev_dbg(dev, "Found existing tags in memory!\n"); + + /* Create procfs directory to hold the last tags */ + last_entry = proc_mkdir_mode(LAST_RDTAGS_PROC_DIR_NAME, + S_IRWXU | S_IRGRP | S_IXGRP, NULL); + if (!last_entry) { + dev_err(dev, "Failed to create last proc entry\n"); + goto exit; + } + + /* Temporarily entry is assigned to create procfs files while + * rebuilding the tags inside /proc/last_rdtags. + */ + entry = last_entry; + + /* Rebuilding the tags as last_rdtags */ + nbr_old_tags = rebuild_tag_tree(last_rdtags_base, rdtags_size); + + /* Initializing entry to NULL, otherwise there is a chance that + * new rdtags will take "last_entry or entry" as a parent + * directory incase failure to create /proc/rdtags. + */ + entry = NULL; + } + + return nbr_old_tags; +exit: + if (last_rdtags_base) { + free_pages((unsigned long)last_rdtags_base, + get_order(rdtags_size)); + last_rdtags_base = NULL; + } + + return ret; +} + +static int rdtags_driver_probe(struct platform_device *pdev) +{ + struct resource *res; + struct rdtags_platform_data *platform_data; + int nbr_old_tags = 0; + int nbr_new_tags = 0; + int ret = 0; + + dev = &pdev->dev; + + /* Get resources */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "rdtags_mem"); + if (!res || !res->start) { + dev_err(dev, "Resource invalid/absent\n"); + ret = -ENODEV; + goto exit; + } + + /* ioremap the static area */ + rdtags_size = res->end - res->start + 1; + rdtags_io_base = (void *)ioremap(res->start, rdtags_size); + if (!rdtags_io_base) { + dev_err(dev, "Failed to map %zd bytes of memory at 0x%llx!\n", + rdtags_size, res->start); + ret = -EINVAL; + goto exit; + } + + nbr_old_tags = last_rdtags_init(); + + rdtags_base = (void *)__get_free_pages(GFP_KERNEL, + get_order(rdtags_size)); + if (!rdtags_base) { + dev_err(dev, "Failed to allocate rdtags buffer\n"); + ret = -ENOMEM; + goto exit; + } + + rdtags_end = rdtags_base + rdtags_size; + memset(rdtags_base, 0x0, rdtags_size); + memset_io(rdtags_io_base, 0x0, rdtags_size); + + /* Add procfs interface */ + entry = proc_create_data(RDTAGS_PROC_NODE_NAME, + S_IFREG | S_IRUGO | S_IWUSR, NULL, + &rdnode_fops, NULL); + if (!entry) { + dev_err(dev, "Failed to create proc entry\n"); + ret = -ENOMEM; + goto exit; + } + + /* Create procfs directory to hold the tags */ + entry = proc_mkdir_mode(RDTAGS_PROC_DIR_NAME, + S_IRWXU | S_IRGRP | S_IXGRP, NULL); + + rdtags_initialized = 1; + + /* Check if the platform has specified a platform specific callback */ + platform_data = dev->platform_data; + if (platform_data && platform_data->platform_init) + nbr_new_tags = platform_data->platform_init + (platform_data->ramdump_mode); + + dev_info(dev, "Loaded with %d existing and " \ + "%d new tags. Size: %zd@0x%.8llx\n", + nbr_old_tags, nbr_new_tags, rdtags_size, res->start); + + return 0; + +exit: + if (rdtags_io_base) { + iounmap(rdtags_io_base); + rdtags_io_base = NULL; + } + + if (rdtags_base) { + free_pages((unsigned long)rdtags_base, get_order(rdtags_size)); + rdtags_base = NULL; + } + + return ret; +} + +static struct platform_driver rdtags_driver = { + .probe = rdtags_driver_probe, + .driver = { + .name = "rdtags", + }, +}; + +static int __init rdtags_core_init(void) +{ + int err; + err = platform_driver_register(&rdtags_driver); + return err; +} + +static void __exit rdtags_module_exit(void) +{ + rdtags_initialized = 0; + + if (entry) { + remove_proc_entry(RDTAGS_PROC_NODE_NAME, NULL); + remove_proc_entry(RDTAGS_PROC_DIR_NAME, NULL); + entry = NULL; + } + + if (last_entry) { + remove_proc_entry(LAST_RDTAGS_PROC_DIR_NAME, NULL); + last_entry = NULL; + } + + /* Unmap everything, but do not clear the area */ + if (rdtags_io_base) { + iounmap(rdtags_io_base); + rdtags_io_base = NULL; + } + + if (last_rdtags_base) { + free_pages((unsigned long)last_rdtags_base, + get_order(rdtags_size)); + last_rdtags_base = NULL; + } + + if (rdtags_base) { + free_pages((unsigned long)rdtags_base, get_order(rdtags_size)); + rdtags_base = NULL; + } + + platform_driver_unregister(&rdtags_driver); +} + +MODULE_AUTHOR("Sony Mobile Communications"); +MODULE_DESCRIPTION("ramdump tags"); +MODULE_LICENSE("GPL V2"); + +core_initcall(rdtags_core_init); +module_exit(rdtags_module_exit); diff --git a/drivers/misc/sim_detect.c b/drivers/misc/sim_detect.c new file mode 100644 index 0000000000000000000000000000000000000000..e064dbddb34f546eeb1ceae1a49d4e1a7a7439b9 --- /dev/null +++ b/drivers/misc/sim_detect.c @@ -0,0 +1,542 @@ +/* drivers/misc/sim_detect.c + * + * Author: Atsushi Iyogi + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIM_DETECT_DEV_NAME "sim_detect" + +struct sim_detect_event_data { + const struct sim_detect_gpio_event *event; + struct timer_list det_timer; + struct work_struct det_work; + unsigned int timer_debounce; + unsigned int irq; +}; + +struct sim_detect_drvdata { + struct device *dev; + struct pinctrl *key_pinctrl; + struct switch_dev sim_detect; + struct mutex lock; + atomic_t detection_in_progress; + unsigned int n_events; + unsigned int current_state; + struct sim_detect_event_data data[0]; +}; + +enum sim_detect_switch_state { + SWITCH_OFF, + SWITCH_ON, +}; + +enum sim_report_state { + NOTHING_HAPPENED = 0, + SIM_REMOVED = 1, + SIM_INSERTED = 2, +}; + +static int sim_detect_gpio_read(struct sim_detect_drvdata *ddata) +{ + int i; + int gpio_state = 0; + + for (i = 0; i < ddata->n_events; i++) + gpio_state += + (gpio_get_value_cansleep(ddata->data[i].event->gpio) + ^ ddata->data[i].event->active_low ? + SWITCH_ON : SWITCH_OFF) << i; + return gpio_state; +} + +static void sim_detect_report_switch_event(struct sim_detect_drvdata *ddata) +{ + int new_state = 0; + int report_state = NOTHING_HAPPENED; + + mutex_lock(&ddata->lock); + + new_state = sim_detect_gpio_read(ddata); + dev_dbg(ddata->dev, "%s: current value(%d) new value(%d)\n", + __func__, ddata->current_state, new_state); + + if (new_state == ddata->current_state) + goto skip_report; + + if (new_state < ddata->current_state) + report_state = SIM_REMOVED; + else if (new_state > ddata->current_state) + report_state = SIM_INSERTED; + + dev_info(ddata->dev, "%s: report (%d)\n", __func__, report_state); + switch_set_state(&ddata->sim_detect, report_state); + ddata->current_state = new_state; + +skip_report: + mutex_unlock(&ddata->lock); +} + +static int sim_detect_get_devtree(struct device *dev, + struct sim_detect_platform_data *pdata) +{ + struct device_node *node, *pp = NULL; + int i = 0; + struct sim_detect_gpio_event *events; + u32 reg; + int gpio; + int ret = -ENODEV; + enum of_gpio_flags flags; + + node = dev->of_node; + if (node == NULL) + goto fail; + + memset(pdata, 0, sizeof(*pdata)); + + pdata->n_events = 0; + pp = NULL; + while ((pp = of_get_next_child(node, pp))) + pdata->n_events++; + + if (pdata->n_events == 0) + goto fail; + + events = kzalloc(pdata->n_events * sizeof(*events), GFP_KERNEL); + if (!events) { + ret = -ENOMEM; + goto fail; + } + + while ((pp = of_get_next_child(node, pp))) { + + if (!of_find_property(pp, "gpios", NULL)) { + pdata->n_events--; + dev_warn(dev, "Found button without gpios\n"); + continue; + } + + gpio = of_get_gpio_flags(pp, 0, &flags); + if (!gpio_is_valid(gpio)) { + dev_err(dev, "%s: invalid gpio %d\n", __func__, gpio); + goto out_fail; + } + events[i].index = i; + events[i].gpio = gpio; + events[i].active_low = flags & OF_GPIO_ACTIVE_LOW; + + events[i].desc = of_get_property(pp, "label", NULL); + + if (of_property_read_u32(pp, "debounce-interval", ®) == 0) + events[i].debounce_interval = reg; + i++; + } + pdata->events = events; + + return 0; + +out_fail: + kfree(events); +fail: + return ret; +} + +static irqreturn_t sim_detect_isr(int irq, void *data) +{ + struct sim_detect_event_data *edata = + (struct sim_detect_event_data *)data; + const struct sim_detect_gpio_event *event = edata->event; + struct sim_detect_drvdata *ddata = container_of(edata, + struct sim_detect_drvdata, + data[event->index]); + + if (edata->timer_debounce) + mod_timer(&edata->det_timer, + jiffies + msecs_to_jiffies(edata->timer_debounce)); + else + schedule_work(&edata->det_work); + + atomic_set(&ddata->detection_in_progress, 1); + + return IRQ_HANDLED; +} + +static void sim_detect_det_tmr_func(unsigned long func_data) +{ + struct sim_detect_event_data *edata = + (struct sim_detect_event_data *)func_data; + + schedule_work(&edata->det_work); +} + +static void sim_detect_det_work(struct work_struct *work) +{ + struct sim_detect_event_data *edata = + container_of(work, struct sim_detect_event_data, det_work); + const struct sim_detect_gpio_event *event = edata->event; + struct sim_detect_drvdata *ddata = container_of(edata, + struct sim_detect_drvdata, + data[event->index]); + + sim_detect_report_switch_event(ddata); + + atomic_set(&ddata->detection_in_progress, 0); +} + +static int sim_detect_pinctrl_configure(struct sim_detect_drvdata *ddata, + bool active) +{ + struct pinctrl_state *set_state; + int retval; + + if (active) { + set_state = + pinctrl_lookup_state(ddata->key_pinctrl, + "tlmm_sim_detect_active"); + if (IS_ERR(set_state)) { + dev_err(ddata->dev, + "cannot get ts pinctrl active state\n"); + goto lookup_err; + } + } else { + set_state = + pinctrl_lookup_state(ddata->key_pinctrl, + "tlmm_sim_detect_suspend"); + if (IS_ERR(set_state)) { + dev_err(ddata->dev, + "cannot get gpiokey pinctrl sleep state\n"); + goto lookup_err; + } + } + retval = pinctrl_select_state(ddata->key_pinctrl, set_state); + if (retval) { + dev_err(ddata->dev, + "cannot set ts pinctrl active state\n"); + goto select_err; + } + + return 0; + +lookup_err: + return PTR_ERR(set_state); +select_err: + return retval; +} + +static int sim_detect_setup_event(struct platform_device *pdev, + struct sim_detect_event_data *edata, + const struct sim_detect_gpio_event *event) +{ + const char *desc = event->desc ? event->desc : SIM_DETECT_DEV_NAME; + struct device *dev = &pdev->dev; + irq_handler_t isr; + unsigned long irqflags; + int irq, error; + + edata->event = event; + + error = gpio_request(event->gpio, desc); + if (error < 0) + dev_warn(dev, "Failed to request GPIO %d, error %d\n", + event->gpio, error); + + error = gpio_direction_input(event->gpio); + if (error < 0) { + dev_err(dev, + "Failed to configure direction for GPIO %d, error %d\n", + event->gpio, error); + goto fail; + } + + edata->timer_debounce = event->debounce_interval; + + irq = gpio_to_irq(event->gpio); + if (irq < 0) { + error = irq; + dev_err(dev, + "Unable to get irq number for GPIO %d, error %d\n", + event->gpio, error); + goto fail; + } + edata->irq = irq; + + isr = sim_detect_isr; + irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; +#ifdef CONFIG_TRAY_SHARED_INTERRUPT_DETECT + irqflags |= IRQF_SHARED; +#endif + + INIT_WORK(&edata->det_work, sim_detect_det_work); + + setup_timer(&edata->det_timer, + sim_detect_det_tmr_func, (unsigned long)edata); + + error = request_any_context_irq(edata->irq, isr, irqflags, desc, edata); + if (error < 0) { + dev_err(dev, "Unable to claim irq %d; error %d\n", + event->irq, error); + goto fail; + } + enable_irq_wake(edata->irq); + + return 0; + +fail: + gpio_free(event->gpio); + return error; +} + +static void sim_detect_remove_event(struct sim_detect_event_data *edata) +{ + free_irq(edata->irq, edata); + if (edata->timer_debounce) + del_timer_sync(&edata->det_timer); + cancel_work_sync(&edata->det_work); + if (gpio_is_valid(edata->event->gpio)) + gpio_free(edata->event->gpio); +} + +static int sim_detect_set_switch_device(struct sim_detect_drvdata *ddata) +{ + int error = 0; + + ddata->sim_detect.name = SIM_DETECT_DEV_NAME; + ddata->sim_detect.state = SWITCH_OFF; + error = switch_dev_register(&ddata->sim_detect); + if (error) { + dev_err(ddata->dev, "%s cannot regist lid(%d)\n", + __func__, error); + } + return error; +} + +static ssize_t sim_attrs_current_state_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sim_detect_drvdata *ddata = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", ddata->current_state); +} + +static struct device_attribute sim_state_attr[] = { + __ATTR(sim_state, S_IRUGO, sim_attrs_current_state_read, NULL), +}; + +static int sim_detect_probe(struct platform_device *pdev) +{ + struct sim_detect_platform_data *pdata = pdev->dev.platform_data; + struct sim_detect_platform_data alt_pdata; + const struct sim_detect_gpio_event *event; + struct sim_detect_event_data *edata; + struct sim_detect_drvdata *ddata; + int i = 0; + int error = 0; + struct pinctrl_state *set_state; + + if (!pdata) { + error = sim_detect_get_devtree(&pdev->dev, &alt_pdata); + if (error) + goto fail; + pdata = &alt_pdata; + } + + ddata = kzalloc(sizeof(struct sim_detect_drvdata) + + pdata->n_events * sizeof(struct sim_detect_event_data), + GFP_KERNEL); + if (!ddata) { + dev_err(&pdev->dev, "failed to allocate drvdata in probe\n"); + error = -ENOMEM; + goto fail; + } + + ddata->dev = &pdev->dev; + ddata->n_events = pdata->n_events; + ddata->key_pinctrl = devm_pinctrl_get(ddata->dev); + mutex_init(&ddata->lock); + + platform_set_drvdata(pdev, ddata); + dev_set_drvdata(ddata->dev, ddata); + + if (IS_ERR(ddata->key_pinctrl)) { + if (PTR_ERR(ddata->key_pinctrl) == -EPROBE_DEFER) + goto fail_pinctrl; + pr_debug("Target does not use pinctrl\n"); + ddata->key_pinctrl = NULL; + } + + if (ddata->key_pinctrl) { + error = sim_detect_pinctrl_configure(ddata, true); + if (error) { + dev_err(ddata->dev, + "cannot set ts pinctrl active state\n"); + goto fail_pinctrl; + } + } + + error = sim_detect_set_switch_device(ddata); + if (error) { + dev_err(ddata->dev, "%s cannot set switch dev(%d)\n", + __func__, error); + goto fail_set_switch; + } + + error = device_create_file(ddata->dev, sim_state_attr); + if (error) { + dev_err(ddata->dev, "%s: create_file failed %d\n", + __func__, error); + goto fail_device_create_file; + } + + for (i = 0; i < pdata->n_events; i++) { + event = &pdata->events[i]; + edata = &ddata->data[i]; + + error = sim_detect_setup_event(pdev, edata, event); + if (error) { + dev_err(ddata->dev, "%s cannot set event error(%d)\n", + __func__, error); + goto fail_setup_event; + } + } + ddata->current_state = sim_detect_gpio_read(ddata); + + dev_warn(ddata->dev, "sim_detect driver was successful.\n"); + return 0; + +fail_setup_event: + device_remove_file(ddata->dev, sim_state_attr); +fail_device_create_file: + switch_dev_unregister(&ddata->sim_detect); +fail_set_switch: + if (ddata->key_pinctrl) { + set_state = + pinctrl_lookup_state(ddata->key_pinctrl, + "tlmm_sim_detect_suspend"); + if (IS_ERR(set_state)) + dev_err(ddata->dev, "cannot get pinctrl sleep state\n"); + else + pinctrl_select_state(ddata->key_pinctrl, set_state); + } + while (--i >= 0) + sim_detect_remove_event(&ddata->data[i]); + platform_set_drvdata(pdev, NULL); +fail_pinctrl: + mutex_destroy(&ddata->lock); + kzfree(ddata); +fail: + return error; +} + +static int sim_detect_remove(struct platform_device *pdev) +{ + int i; + struct sim_detect_drvdata *ddata = platform_get_drvdata(pdev); + + device_remove_file(ddata->dev, sim_state_attr); + switch_dev_unregister(&ddata->sim_detect); + mutex_destroy(&ddata->lock); + for (i = 0; i < ddata->n_events; i++) + sim_detect_remove_event(&ddata->data[i]); + if (!pdev->dev.platform_data) + kfree(ddata->data[0].event); + kzfree(ddata); + + return 0; +} + +static int sim_detect_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct sim_detect_drvdata *ddata = platform_get_drvdata(pdev); + int ret = 0; + + if (atomic_read(&ddata->detection_in_progress)) { + dev_dbg(&pdev->dev, "detection in progress. (%s)\n", + __func__); + ret = -EAGAIN; + goto out; + } + + if (ddata->key_pinctrl) { + ret = sim_detect_pinctrl_configure(ddata, false); + if (ret) + dev_err(&pdev->dev, "failed to put the pin\n"); + } + +out: + return ret; +} + +static int sim_detect_resume(struct platform_device *pdev) +{ + struct sim_detect_drvdata *ddata = platform_get_drvdata(pdev); + int ret = 0; + + if (ddata->key_pinctrl) { + ret = sim_detect_pinctrl_configure(ddata, true); + if (ret) + dev_err(&pdev->dev, "failed to put the pin\n"); + } + + return ret; +} + +static struct of_device_id sim_detect_match_table[] = { + { .compatible = "sim-detect", + }, + {} +}; + +static struct platform_driver sim_detect_driver = { + .probe = sim_detect_probe, + .remove = sim_detect_remove, + .suspend = sim_detect_suspend, + .resume = sim_detect_resume, + .driver = { + .name = SIM_DETECT_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = sim_detect_match_table, + }, +}; + +static int __init sim_detect_init(void) +{ + return platform_driver_register(&sim_detect_driver); +} + +static void __exit sim_detect_exit(void) +{ + platform_driver_unregister(&sim_detect_driver); +} + +late_initcall(sim_detect_init); +module_exit(sim_detect_exit); + +MODULE_LICENSE("GPLv2"); + diff --git a/drivers/misc/tcs3490.c b/drivers/misc/tcs3490.c new file mode 100644 index 0000000000000000000000000000000000000000..02a4e943bf4ed76210398cbb0749d772b03cc379 --- /dev/null +++ b/drivers/misc/tcs3490.c @@ -0,0 +1,1650 @@ +/* + * Device driver for monitoring ambient light intensity in (lux), RGB, and + * color temperature (in kelvin) within the AMS-TAOS TCS family of devices. + * + * Copyright (c) 2016, AMS-TAOS USA, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tcs3490.h" + +// +// Debug options +// + +// Create an ABI for dumping CHIP_ID, REV_ID, and colorbin register contents? +#define CHIP_ID_ABI 1 + +// Print info re lux calculations (printed per sample, potentially voluminous)? +//#define LUX_MESSAGES 1 + + +// +// Configurational options +// + +// Define this as nonzero, or not, depending on your system configuration. +// The color-bin correction factors need to be applied at a different +// point in the computation with inked glass vs. air or clear glass. +#define INKED_GLASS 0 + + +// +// Constants +// + +#define TCS3490_CMD_ALS_INT_CLR 0xE6 +#define TCS3490_CMD_ALL_INT_CLR 0xE7 +#define TCS3490_CHANNEL 0xC0 + +#define CENTI_MSEC_PER_ATIME_TICK 278 +#define CENTI_MSEC_PER_MSEC 100 + +#define I2C_ADDR_OFFSET 0x80 + +#define GAIN1 0 +#define GAIN4 1 +#define GAIN16 2 +#define GAIN64 3 + +#define TCS3490_MAX_INTEGRATION_CYCLES 256 + +// +// pertaining to the Color Bins register, used for improved color accuracy +// + +#define _Q 16 // fixed point arithmetic shift + +#define COLOR_BINS_MSK_COEFF (1 << 15) +#define CONFIG_SPARE_2_MSK (1 << 3) + +#define COLOR_BINS_SHFT_RED 11 +#define COLOR_BINS_MSK_RED (((1 << 4) - 1) << COLOR_BINS_SHFT_RED) +#define COLOR_BINS_INT_MSK_RED ((1 << (4-1)) - 1) + +#define COLOR_BINS_SHFT_GRN 6 +#define COLOR_BINS_MSK_GRN (((1 << 5) - 1) << COLOR_BINS_SHFT_GRN) +#define COLOR_BINS_INT_MSK_GRN ((1 << (5-1)) - 1) + +#define COLOR_BINS_SHFT_BLU 0 +#define COLOR_BINS_MSK_BLU (((1 << 6) - 1) << COLOR_BINS_SHFT_BLU) +#define COLOR_BINS_INT_MSK_BLU ((1 << (6-1)) - 1) + +// These are processed only at compile time; there is no floating point +// arithmetic at runtime +#define SLOPE_RED (-0.0111) +#define OFFSET_RED (1.0174) +#define SLOPE_GRN (-0.0110) +#define OFFSET_GRN (1.0602) +#define SLOPE_BLU (-0.0074) +#define OFFSET_BLU (1.0631) + +#define RGBCIR_SENSOR_SYSFS_LINK_NAME "rgbcir_sensor" +#define RGBCIR_SENSOR_PINCTRL_IRQ_ACTIVE "rgbcir_irq_active" +#define RGBCIR_SENSOR_PINCTRL_IRQ_SUSPEND "rgbcir_irq_suspend" +#define RGBCIR_SENSOR_REGULATOR_NOTIFY_PRIORITY (1000) + +enum tcs3490_regs { + TCS3490_CONTROL, + TCS3490_ALS_TIME, // 0x81 + TCS3490_RESV_1, + TCS3490_WAIT_TIME, // 0x83 + TCS3490_ALS_MINTHRESHLO, // 0x84 + TCS3490_ALS_MINTHRESHHI, // 0x85 + TCS3490_ALS_MAXTHRESHLO, // 0x86 + TCS3490_ALS_MAXTHRESHHI, // 0x87 + TCS3490_RESV_2, // 0x88 + TCS3490_PRX_MINTHRESHLO, // 0x89 -> Not used for TCS3490 + + TCS3490_RESV_3, // 0x8A + TCS3490_PRX_MAXTHRESHHI, // 0x8B -> Not used for TCS3490 + TCS3490_PERSISTENCE, // 0x8C + TCS3490_CONFIG, // 0x8D + TCS3490_PRX_PULSE_COUNT, // 0x8E -> Not used for TCS3490 + TCS3490_GAIN, // 0x8F : Gain Control Register + TCS3490_AUX, // 0x90 + TCS3490_REVID, + TCS3490_CHIPID, + TCS3490_STATUS, // 0x93 + + TCS3490_CLR_CHANLO, // 0x94 + TCS3490_CLR_CHANHI, // 0x95 + TCS3490_RED_CHANLO, // 0x96 + TCS3490_RED_CHANHI, // 0x97 + TCS3490_GRN_CHANLO, // 0x98 + TCS3490_GRN_CHANHI, // 0x99 + TCS3490_BLU_CHANLO, // 0x9A + TCS3490_BLU_CHANHI, // 0x9B + TCS3490_PRX_HI, // 0x9C + TCS3490_PRX_LO, // 0x9D + + TCS3490_PRX_OFFSET, // 0x9E + TCS3490_RESV_4, // 0x9F + TCS3490_IRBEAM_CFG, // 0xA0 + TCS3490_IRBEAM_CARR, // 0xA1 + TCS3490_IRBEAM_NS, // 0xA2 + TCS3490_IRBEAM_ISD, // 0xA3 + TCS3490_IRBEAM_NP, // 0xA4 + TCS3490_IRBEAM_IPD, // 0xA5 + TCS3490_IRBEAM_DIV, // 0xA6 + TCS3490_IRBEAM_LEN, // 0xA7 + + TCS3490_IRBEAM_STAT, // 0xA8 + + TCS3490_REG_COLOR_BINLO=0x55, // 0xD5 + TCS3490_REG_COLOR_BINHI=0x56, // 0xD6 + + TCS3490_REG_MAX, + +}; + +enum tcs3490_en_reg { + TCS3490_EN_PWR_ON = (1 << 0), + TCS3490_EN_ALS = (1 << 1), + TCS3490_EN_PRX = (1 << 2), + TCS3490_EN_WAIT = (1 << 3), + TCS3490_EN_ALS_IRQ = (1 << 4), + TCS3490_EN_PRX_IRQ = (1 << 5), + TCS3490_EN_IRQ_PWRDN = (1 << 6), + TCS3490_EN_BEAM = (1 << 7), +}; + +enum tcs3490_status { + TCS3490_ST_ALS_VALID = (1 << 0), + TCS3490_ST_PRX_VALID = (1 << 1), + TCS3490_ST_BEAM_IRQ = (1 << 3), + TCS3490_ST_ALS_IRQ = (1 << 4), + TCS3490_ST_PRX_IRQ = (1 << 5), + TCS3490_ST_PRX_SAT = (1 << 6), +}; + +enum { + TCS3490_ALS_GAIN_MASK = (3 << 0), + TCS3490_PRX_GAIN_MASK = (3 << 2), + TCS3490_ALS_AGL_MASK = (1 << 2), + TCS3490_ALS_AGL_SHIFT = 2, + TCS3490_ATIME_PER_100 = 273, + TCS3490_ATIME_DEFAULT_MS = 50, + SCALE_SHIFT = 11, + RATIO_SHIFT = 10, + MAX_ALS_VALUE = 0xffff, + MIN_ALS_VALUE = 10, + GAIN_SWITCH_LEVEL = 100, + GAIN_AUTO_INIT_VALUE = AGAIN_16, +}; + +static u8 const restorable_regs[] = { + TCS3490_ALS_TIME, + TCS3490_PERSISTENCE, + TCS3490_GAIN, +}; + +static u8 const als_gains[] = { + 1, + 4, + 16, + 64 +}; + +struct tcs3490_als_info { + u32 saturation; + u16 clear_red_raw; + u16 clear_green_raw; + u16 clear_blue_raw; + u16 clear_raw; + u16 red_raw; + u16 green_raw; + u16 blue_raw; + u16 ir_raw; + uint64_t timestamp; +}; + +struct tcs3490_chip { + struct mutex lock; + struct i2c_client *client; + struct tcs3490_als_info als_inf; + struct tcs3490_parameters params; + struct tcs3490_i2c_platform_data *pdata; + u8 shadow[42]; + + struct input_dev *a_idev; + int in_suspend; + int wake_irq; + int irq_pending; + bool unpowered; + bool als_enabled; + bool is_register_regulator_cam_vio_notify; + int als_thres_enabled; + int als_switch_ch_enabled; + int vdd_supply_enable; + int gpio_vdd_enable; + int vio_supply_enable; + + bool als_gain_auto; + u8 als_channel; + u8 device_index; + struct regulator *vdd; + struct regulator *gpio_vdd; + struct regulator *vio; + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + struct notifier_block cam_io_regulator_cb; +}; + +static int tcs3490_power_on(struct tcs3490_chip *chip); +static int tcs3490_pltf_power_off(struct tcs3490_chip *chip); + +static int tcs3490_pinctrl_init(struct tcs3490_chip *data) +{ + data->pinctrl = devm_pinctrl_get(&data->client->dev); + if (IS_ERR_OR_NULL(data->pinctrl)) { + dev_err(&data->client->dev, + "%s:%d Getting pinctrl handle failed\n", + __func__, __LINE__); + return -EINVAL; + } + data->gpio_state_active = + pinctrl_lookup_state(data->pinctrl, + RGBCIR_SENSOR_PINCTRL_IRQ_ACTIVE); + if (IS_ERR_OR_NULL(data->gpio_state_active)) { + dev_err(&data->client->dev, + "%s:Failed to get the active state pinctrl handle\n", + __func__); + return -EINVAL; + } + data->gpio_state_suspend = + pinctrl_lookup_state(data->pinctrl, + RGBCIR_SENSOR_PINCTRL_IRQ_SUSPEND); + if (IS_ERR_OR_NULL(data->gpio_state_suspend)) { + dev_err(&data->client->dev, + "%s:Failed to get the suspend state pinctrl handle\n", + __func__); + return -EINVAL; + } + return 0; +} + +static int tcs3490_i2c_blk_read(struct tcs3490_chip *chip, + u8 reg, u8 *val, int size) +{ + s32 ret; + struct i2c_client *client = chip->client; + + uint8_t w_buf[1]; + uint8_t *r_buf; + struct i2c_msg msg[2]; + + reg |= I2C_ADDR_OFFSET; + w_buf[0] = reg; + msg[0].addr = (client->addr) >> 1; + msg[0].flags = 0; + msg[0].buf = w_buf; + msg[0].len = 1; + + r_buf = kmalloc(size + 1, GFP_KERNEL); + if (!r_buf) + return -ENOMEM; + memset(r_buf, 0, size); + msg[1].addr = (client->addr) >> 1; + msg[1].flags = I2C_M_RD; + msg[1].buf = r_buf; + msg[1].len = size; + ret = i2c_transfer(client->adapter, msg, 2); + if (ret != 2) { + usleep_range(3000, 4000); + ret = i2c_transfer(client->adapter, msg, 2); + if (ret != 2) { + dev_err(&client->dev, + "%s: i2c ERROR !! reg=0x%x ret=%d\n", + __func__, reg, ret); + kfree(r_buf); + return ret; + } + } else { + ret = 0; + } + memcpy(val, r_buf, sizeof(u8) * size); + kfree(r_buf); + + return ret; +} + +static int tcs3490_i2c_read(struct tcs3490_chip *chip, u8 reg, u8 *val) +{ + int ret; + struct i2c_client *client = chip->client; + uint8_t w_buf[1]; + uint8_t r_buf[1]; + struct i2c_msg msg[2]; + + reg |= I2C_ADDR_OFFSET; + w_buf[0] = reg; + msg[0].addr = (client->addr) >> 1; + msg[0].flags = 0; + msg[0].buf = w_buf; + msg[0].len = 1; + + r_buf[0] = 0x0; + msg[1].addr = (client->addr) >> 1; + msg[1].flags = I2C_M_RD; + msg[1].buf = r_buf; + msg[1].len = 1; + ret = i2c_transfer(client->adapter, msg, 2); + if (ret != 2) { + usleep_range(3000, 4000); + ret = i2c_transfer(client->adapter, msg, 2); + if (ret != 2) { + dev_err(&client->dev, + "%s: i2c ERROR !! reg=0x%x ret=%d\n", + __func__, reg, ret); + return ret; + } + } else { + ret = 0; + } + *val = r_buf[0]; + + return 0; +} + +static int tcs3490_i2c_write(struct tcs3490_chip *chip, u8 reg, u8 val) +{ + int ret; + struct i2c_client *client = chip->client; + + uint8_t w_buf[2]; + struct i2c_msg msg[1]; + + if (reg == TCS3490_CONTROL) { + dev_dbg(&client->dev, "%s: CONTRL addr[0x%x] data[0x%x]", + __func__, reg, val); + } + + reg |= I2C_ADDR_OFFSET; + w_buf[0] = reg; + w_buf[1] = val; + msg[0].addr = (client->addr) >> 1; + msg[0].flags = 0; + msg[0].buf = w_buf; + msg[0].len = 2; + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + usleep_range(3000, 4000); + ret = i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + dev_err(&client->dev, + "%s: i2c ERROR !! reg=0x%x ret=%d\n", + __func__, reg, ret); + ret = -1; + } + } else { + ret = 0; + } + + return ret; +} + +static int tcs3490_i2c_reg_blk_write(struct tcs3490_chip *chip, + u8 reg, u8 *val, int size) +{ + s32 ret; + struct i2c_client *client = chip->client; + + uint8_t *w_buf; + struct i2c_msg msg[2]; + + reg |= I2C_ADDR_OFFSET; + w_buf = kmalloc(size + 1, GFP_KERNEL); + if (!w_buf) { + dev_err(&client->dev, "%s: failed to allocate buffer", + __func__); + return -ENOMEM; + } + w_buf[0] = reg; + memmove(&w_buf[1], val, size); + msg[0].addr = (client->addr) >> 1; + msg[0].flags = 0; + msg[0].buf = w_buf; + msg[0].len = size + 1; + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + usleep_range(3000, 4000); + ret = i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + dev_err(&client->dev, + "%s: i2c ERROR !! reg=0x%x ret=%d\n", + __func__, reg, ret); + } + } else { + ret = 0; + } + kfree(w_buf); + + return ret; +} + +static int tcs3490_flush_regs(struct tcs3490_chip *chip) +{ + unsigned i; + int rc; + u8 reg; + + for (i = 0; i < ARRAY_SIZE(restorable_regs); i++) { + reg = restorable_regs[i]; + rc = tcs3490_i2c_write(chip, reg, chip->shadow[reg]); + if (rc) { + dev_err(&chip->client->dev, "%s: err on reg 0x%02x\n", + __func__, reg); + break; + } + } + return rc; +} + +static int tcs3490_update_enable_reg(struct tcs3490_chip *chip) +{ + dev_info(&chip->client->dev, "%s: Writing CONTROL, val[0x0%x]", + __func__, chip->shadow[TCS3490_CONTROL]); + return tcs3490_i2c_write(chip, TCS3490_CONTROL, + chip->shadow[TCS3490_CONTROL]); +} + +static int tcs3490_set_als_gain(struct tcs3490_chip *chip, int gain) +{ + int rc; + u8 ctrl_reg = chip->shadow[TCS3490_GAIN] & ~TCS3490_ALS_GAIN_MASK; + + switch (gain) { + case 1: + ctrl_reg |= AGAIN_1; + break; + case 4: + ctrl_reg |= AGAIN_4; + break; + case 16: + ctrl_reg |= AGAIN_16; + break; + case 64: + ctrl_reg |= AGAIN_64; + break; + default: + dev_err(&chip->client->dev, "%s: wrong als gain %d\n", + __func__, gain); + return -EINVAL; + } + + rc = tcs3490_i2c_write(chip, TCS3490_GAIN, ctrl_reg); + if (!rc) { + chip->shadow[TCS3490_GAIN] = ctrl_reg; + chip->params.als_gain = gain; + dev_info(&chip->client->dev, "%s: new als gain %d\n", + __func__, gain); + } + return rc; +} + + +static int tcs3490_irq_clr(struct tcs3490_chip *chip, u8 int2clr) +{ + int ret; + + ret = tcs3490_i2c_write(chip, int2clr, 0); + if (ret) { + dev_err(&chip->client->dev, "%s: failed 2x, int to clr %02x\n", + __func__, int2clr); + } + + return ret; +} + +static void tcs3490_get_als_setup_next(struct tcs3490_chip *chip) +{ + u8 *buf; + u32 sat; + int rc; + u8 atime = 0; + u8 cur_channel = 0xFF; + ktime_t cur_ktime; + + mutex_lock(&chip->lock); + buf = &chip->shadow[TCS3490_CLR_CHANLO]; + atime = chip->shadow[TCS3490_ALS_TIME]; + mutex_unlock(&chip->lock); + + tcs3490_i2c_read(chip, TCS3490_CHANNEL, &cur_channel); + if ((chip->als_switch_ch_enabled == 1) && (cur_channel == 0x00)) { + /*RGBC*/ + /*extract raw channel data*/ + mutex_lock(&chip->lock); + chip->als_inf.clear_raw = + le16_to_cpup((const __le16 *)&buf[0]); + chip->als_inf.clear_red_raw = + le16_to_cpup((const __le16 *)&buf[2]); + chip->als_inf.clear_green_raw = + le16_to_cpup((const __le16 *)&buf[4]); + chip->als_inf.clear_blue_raw = + le16_to_cpup((const __le16 *)&buf[6]); + mutex_unlock(&chip->lock); + + /*Switch to RGB-IR*/ + rc = tcs3490_i2c_write(chip, TCS3490_CHANNEL, 0x80); + if (!rc) { + dev_dbg(&chip->client->dev, + "%s: Channel: RGB-IR", __func__); + mutex_lock(&chip->lock); + chip->als_channel = 0x80; + mutex_unlock(&chip->lock); + } + dev_dbg(&chip->client->dev, + "%s: Changed ALS channel from RGBC to 0x%x\n", + __func__, chip->als_channel); + } else if ((chip->als_switch_ch_enabled == 1) && + (cur_channel == 0x80)) { + /*RGBC-IR*/ + /*extract ir channel data*/ + mutex_lock(&chip->lock); + chip->als_inf.ir_raw = + le16_to_cpup((const __le16 *)&buf[0]); + chip->als_inf.red_raw = + le16_to_cpup((const __le16 *)&buf[2]); + chip->als_inf.green_raw = + le16_to_cpup((const __le16 *)&buf[4]); + chip->als_inf.blue_raw = + le16_to_cpup((const __le16 *)&buf[6]); + mutex_unlock(&chip->lock); + /*Switch to RGBC*/ + rc = tcs3490_i2c_write(chip, TCS3490_CHANNEL, 0x00); + if (!rc) { + dev_dbg(&chip->client->dev, "%s: Channel: RGBC", + __func__); + mutex_lock(&chip->lock); + chip->als_channel = 0x00; + mutex_unlock(&chip->lock); + } + cur_ktime = ktime_get(); + chip->als_inf.timestamp = (uint64_t)cur_ktime.tv64; + dev_dbg(&chip->client->dev, + "%s: Changed channel from RGBC-IR to 0x%x Time %llu\n", + __func__, chip->als_channel, chip->als_inf.timestamp); + } else { + if (cur_channel == 0x00) { + mutex_lock(&chip->lock); + chip->als_inf.clear_raw = + le16_to_cpup((const __le16 *)&buf[0]); + mutex_unlock(&chip->lock); + } else { + mutex_lock(&chip->lock); + chip->als_inf.ir_raw = + le16_to_cpup((const __le16 *)&buf[0]); + mutex_unlock(&chip->lock); + } + mutex_lock(&chip->lock); + chip->als_inf.red_raw = + le16_to_cpup((const __le16 *)&buf[2]); + chip->als_inf.green_raw = + le16_to_cpup((const __le16 *)&buf[4]); + chip->als_inf.blue_raw = + le16_to_cpup((const __le16 *)&buf[6]); + mutex_unlock(&chip->lock); + cur_ktime = ktime_get(); + chip->als_inf.timestamp = (uint64_t)cur_ktime.tv64; + } + + sat = min_t(u32, MAX_ALS_VALUE, + (u32)(TCS3490_MAX_INTEGRATION_CYCLES - atime) << 10); + sat = sat * 8 / 10; + chip->als_inf.saturation = sat; + + dev_dbg(&chip->client->dev, + "%s: raw c/ir,r,g,b: %d, %d, %d, %d\n", + __func__, + (cur_channel == 0x00) ? + chip->als_inf.clear_raw : chip->als_inf.ir_raw, + chip->als_inf.red_raw, + chip->als_inf.green_raw, + chip->als_inf.blue_raw); +} + +static int tcs3490_read_all(struct tcs3490_chip *chip) +{ + int ret = 0; + + mutex_lock(&chip->lock); + tcs3490_i2c_read(chip, TCS3490_STATUS, + &chip->shadow[TCS3490_STATUS]); + + ret = tcs3490_i2c_blk_read(chip, TCS3490_CLR_CHANLO, + &chip->shadow[TCS3490_CLR_CHANLO], 2); + ret = tcs3490_i2c_blk_read(chip, TCS3490_RED_CHANLO, + &chip->shadow[TCS3490_RED_CHANLO], 2); + ret = tcs3490_i2c_blk_read(chip, TCS3490_GRN_CHANLO, + &chip->shadow[TCS3490_GRN_CHANLO], 2); + ret = tcs3490_i2c_blk_read(chip, TCS3490_BLU_CHANLO, + &chip->shadow[TCS3490_BLU_CHANLO], 2); + mutex_unlock(&chip->lock); + return (ret < 0) ? ret : 0; +} + +static int tcs3490_update_als_thres(struct tcs3490_chip *chip, bool on_enable) +{ + s32 ret; + u8 *buf = &chip->shadow[TCS3490_ALS_MINTHRESHLO]; + u16 deltaP = chip->params.als_deltaP; + u16 from, to, cur; + u16 saturation = chip->als_inf.saturation; + + mutex_lock(&chip->lock); + cur = chip->als_inf.clear_raw; + mutex_unlock(&chip->lock); + + if (!on_enable) + /* move deltaP far away from current position to force an irq */ + from = to = cur > saturation / 2 ? 0 : saturation; + else { + deltaP = cur * deltaP / 100; + if (!deltaP) + deltaP = 1; + if (cur > deltaP) + from = cur - deltaP; + else + from = 0; + if (cur < (saturation - deltaP)) + to = cur + deltaP; + else + to = saturation; + } + + *buf++ = from & 0xff; + *buf++ = from >> 8; + *buf++ = to & 0xff; + *buf++ = to >> 8; + mutex_lock(&chip->lock); + ret = tcs3490_i2c_reg_blk_write(chip, TCS3490_ALS_MINTHRESHLO, + &chip->shadow[TCS3490_ALS_MINTHRESHLO], + TCS3490_ALS_MAXTHRESHHI - TCS3490_ALS_MINTHRESHLO + 1); + mutex_unlock(&chip->lock); + + dev_info(&chip->client->dev, + "%s: on_enable[%s] cur[%u] deltaP[%u] from[%u] to[%u]", + __func__, on_enable?"TRUE":"FALSE", cur, deltaP, from, to); + + return (ret < 0) ? ret : 0; +} + +static int tcs3490_check_and_report(struct tcs3490_chip *chip) +{ + u8 status; + u8 saturation; + + int ret = tcs3490_read_all(chip); + if (ret) + goto exit_clr; + + mutex_lock(&chip->lock); + status = chip->shadow[TCS3490_STATUS]; + mutex_unlock(&chip->lock); + + saturation = chip->als_inf.saturation; + + if ((status & (TCS3490_ST_ALS_VALID | TCS3490_ST_ALS_IRQ)) == + (TCS3490_ST_ALS_VALID | TCS3490_ST_ALS_IRQ)) { + tcs3490_get_als_setup_next(chip); + tcs3490_irq_clr(chip, TCS3490_CMD_ALS_INT_CLR); + if (chip->als_thres_enabled) + tcs3490_update_als_thres(chip, 1); + } + +exit_clr: + tcs3490_irq_clr(chip, TCS3490_CMD_ALL_INT_CLR); + + return ret; +} + +static irqreturn_t tcs3490_irq(int irq, void *handle) +{ + struct tcs3490_chip *chip = handle; + + (void)tcs3490_check_and_report(chip); + sysfs_notify(&chip->a_idev->dev.kobj, NULL, "notify"); + return IRQ_HANDLED; +} + +static void tcs3490_set_defaults(struct tcs3490_chip *chip) +{ + u8 *sh = chip->shadow; + struct device *dev = &chip->client->dev; + + dev_info(dev, "%s: use defaults\n", __func__); + mutex_lock(&chip->lock); + sh[TCS3490_ALS_TIME] = 0xFE;/*0xEE;*/ /* integration time : 254 ms */ + mutex_unlock(&chip->lock); + sh[TCS3490_WAIT_TIME] = 0xFF; /* wait time : 2.4 ms */ + sh[TCS3490_PERSISTENCE] = ALS_PERSIST(0); + sh[TCS3490_PRX_PULSE_COUNT] = 8; + sh[TCS3490_GAIN] = AGAIN_1;/*AGAIN_16;*/ + sh[TCS3490_AUX] = 0x00; /* No saturation int */ + + chip->als_gain_auto = false; + mutex_lock(&chip->lock); + chip->als_channel = 0x00; /* Clear channel */ + mutex_unlock(&chip->lock); + chip->als_switch_ch_enabled = 1; /* Obtain RGBC and IR in turn */ +} + +static ssize_t tcs3490_chip_pow_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->unpowered ? 0 : 1); +} + +static ssize_t tcs3490_chip_pow_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + int rc = 0; + bool value; + + dev_info(&chip->client->dev, "CHK 1 %s\n", __func__); + + if (strtobool(buf, &value)) + return -EINVAL; + + dev_info(&chip->client->dev, "CHK 2 %s: value = %s\n", + __func__, value?"TRUE":"FALSE"); + + if (value) { + if (!rc && chip->unpowered) + tcs3490_power_on(chip); + if (!rc && chip->pinctrl && chip->gpio_state_active) { + rc = pinctrl_select_state(chip->pinctrl, + chip->gpio_state_active); + if (rc) + dev_err(&chip->client->dev, + "%s: cannot set pin to active state", + __func__); + } + if (!rc) { + dev_info(&chip->client->dev, + "tcs3490: Request threaded IRQ\n"); + rc = request_threaded_irq(chip->client->irq, NULL, + &tcs3490_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(&chip->client->dev), chip); + if (rc) { + dev_info(&chip->client->dev, + "Failed to request irq %d\n", + chip->client->irq); + (void)pinctrl_select_state(chip->pinctrl, + chip->gpio_state_suspend); + } + } + if (rc) + tcs3490_pltf_power_off(chip); + } else { + if (chip->pinctrl && chip->gpio_state_suspend) { + free_irq(chip->client->irq, chip); + rc = pinctrl_select_state(chip->pinctrl, + chip->gpio_state_suspend); + if (rc) + dev_err(&chip->client->dev, + "%s: cannot set pin to active state", + __func__); + } + if (!chip->unpowered) + tcs3490_pltf_power_off(chip); + } + + return size; +} + +static int tcs3490_als_enable(struct tcs3490_chip *chip, int on) +{ + int rc; + + dev_info(&chip->client->dev, "%s: on = %d\n", __func__, on); + if (on) { + tcs3490_irq_clr(chip, TCS3490_CMD_ALS_INT_CLR); + tcs3490_update_als_thres(chip, 1); + chip->shadow[TCS3490_CONTROL] |= + (TCS3490_EN_PWR_ON | TCS3490_EN_ALS | + TCS3490_EN_ALS_IRQ); + + rc = tcs3490_update_enable_reg(chip); + if (rc) + return rc; + mdelay(3); + } else { + chip->shadow[TCS3490_CONTROL] &= + ~(TCS3490_EN_ALS_IRQ); + + if (!(chip->shadow[TCS3490_CONTROL] & TCS3490_EN_PRX)) + chip->shadow[TCS3490_CONTROL] &= ~TCS3490_EN_PWR_ON; + rc = tcs3490_update_enable_reg(chip); + if (rc) + return rc; + chip->als_inf.timestamp = 0; + tcs3490_irq_clr(chip, TCS3490_CMD_ALS_INT_CLR); + } + if (!rc) + chip->als_enabled = on; + + return rc; +} + +static ssize_t tcs3490_als_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", chip->als_enabled); +} + +static ssize_t tcs3490_als_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + bool value; + + if (strtobool(buf, &value)) + return -EINVAL; + + if (value) + tcs3490_als_enable(chip, 1); + else + tcs3490_als_enable(chip, 0); + + return size; +} + +static ssize_t tcs3490_auto_gain_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%s\n", + chip->als_gain_auto ? "auto" : "manual"); +} + +static ssize_t tcs3490_auto_gain_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + bool value; + + if (strtobool(buf, &value)) + return -EINVAL; + + if (value) + chip->als_gain_auto = true; + else + chip->als_gain_auto = false; + + return size; +} + +static ssize_t tcs3490_als_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", + chip->params.als_gain); +} + +static ssize_t tcs3490_als_all_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + + mutex_lock(&chip->lock); + ret = snprintf(buf, PAGE_SIZE, "%u,%u,%u,%u,%u,%u,%u,%u,%llu", + chip->als_inf.clear_red_raw, + chip->als_inf.clear_green_raw, + chip->als_inf.clear_blue_raw, + chip->als_inf.clear_raw, + chip->als_inf.red_raw, + chip->als_inf.green_raw, + chip->als_inf.blue_raw, + chip->als_inf.ir_raw, + chip->als_inf.timestamp); + mutex_unlock(&chip->lock); + return ret; +} + +static ssize_t tcs3490_als_red_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + mutex_lock(&chip->lock); + ret = snprintf(buf, PAGE_SIZE, "%d", chip->als_inf.red_raw); + mutex_lock(&chip->lock); + return ret; +} + +static ssize_t tcs3490_als_green_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + mutex_lock(&chip->lock); + ret = snprintf(buf, PAGE_SIZE, "%d", chip->als_inf.green_raw); + mutex_unlock(&chip->lock); + return ret; +} + +static ssize_t tcs3490_als_blue_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + mutex_lock(&chip->lock); + ret = snprintf(buf, PAGE_SIZE, "%d", chip->als_inf.blue_raw); + mutex_unlock(&chip->lock); + return ret; +} + +static ssize_t tcs3490_als_clear_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + mutex_lock(&chip->lock); + ret = snprintf(buf, PAGE_SIZE, "%d", chip->als_inf.clear_raw); + mutex_unlock(&chip->lock); + return ret; +} + +static ssize_t tcs3490_als_gain_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long gain; + int rc; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 10, &gain); + + if (rc) + return -EINVAL; + if (gain != 0 && gain != 1 && gain != 4 && gain != 16 && + gain != 60 && gain != 64) + return -EINVAL; + + mutex_lock(&chip->lock); + if (gain) { + chip->als_gain_auto = false; + rc = tcs3490_set_als_gain(chip, gain); + } else { + chip->als_gain_auto = true; + } + tcs3490_flush_regs(chip); + mutex_unlock(&chip->lock); + return rc ? rc : size; +} + +static ssize_t tcs3490_als_persist_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d", + (((chip->params.persist) & 0x0f))); +} + +static ssize_t tcs3490_als_persist_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + long persist; + int rc; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 10, &persist); + if (rc) + return -EINVAL; + + mutex_lock(&chip->lock); + chip->shadow[TCS3490_PERSISTENCE] &= 0xF0; + chip->shadow[TCS3490_PERSISTENCE] |= ((u8)persist & 0x0F); + + rc = tcs3490_flush_regs(chip); + if (!rc) + chip->params.persist = chip->shadow[TCS3490_PERSISTENCE]; + mutex_unlock(&chip->lock); + return size; +} + +static ssize_t tcs3490_als_itime_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + int t; + mutex_lock(&chip->lock); + t = TCS3490_MAX_INTEGRATION_CYCLES - chip->params.als_time; + mutex_unlock(&chip->lock); + return snprintf(buf, PAGE_SIZE, "%d\n", t); +} + +static ssize_t tcs3490_als_itime_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + long itime; + int rc; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 10, &itime); + if (rc) + return -EINVAL; + + mutex_lock(&chip->lock); + chip->shadow[TCS3490_ALS_TIME] = + TCS3490_MAX_INTEGRATION_CYCLES - (u8)itime; + rc = tcs3490_flush_regs(chip); + if (!rc) + chip->params.als_time = chip->shadow[TCS3490_ALS_TIME]; + mutex_unlock(&chip->lock); + return size; +} + +static ssize_t tcs3490_als_thres_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d", chip->als_thres_enabled); +} + +static ssize_t tcs3490_als_thres_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + int rc; + int on_enable; + + rc = kstrtoint(buf, 10, &on_enable); + + if (rc) + return -EINVAL; + + if (on_enable == 1) + tcs3490_update_als_thres(chip, 1); + else + tcs3490_update_als_thres(chip, 0); + chip->als_thres_enabled = 1; + return size; +} + +static ssize_t tcs3490_als_deltaP_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, + "%d (in %%)", chip->params.als_deltaP); +} + +static ssize_t tcs3490_als_deltaP_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long deltaP; + int rc; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 10, &deltaP); + if (rc || deltaP > 100) + return -EINVAL; + mutex_lock(&chip->lock); + chip->params.als_deltaP = deltaP; + mutex_unlock(&chip->lock); + dev_info(&chip->client->dev, + "%s: Changed ALS deltaP, deltaP[%lu]", + __func__, deltaP); + return size; +} + +/*=========== Switch IR/Clear channel ==================*/ +static ssize_t tcs3490_als_channel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + + mutex_lock(&chip->lock); + ret = snprintf(buf, PAGE_SIZE, "%d", + ((chip->als_channel & 0x80) == 0x00) ? 0 : 1); + mutex_unlock(&chip->lock); + return ret; +} + +static ssize_t tcs3490_als_channel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long channel; + u8 ch_val = 0; + int rc; + struct tcs3490_chip *chip = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 10, &channel); + if (rc || channel > 2) + return -EINVAL; + + ch_val = (channel == 0) ? 0x00 : 0x80; + rc = tcs3490_i2c_write(chip, TCS3490_CHANNEL, ch_val); + if (!rc) { + dev_info(&chip->client->dev, "%s: new channel %s\n", + __func__, ((ch_val & 0x80) == 0x00) ? "clear" : "ir"); + mutex_lock(&chip->lock); + chip->als_channel = ch_val; + mutex_unlock(&chip->lock); + } + return size; +} +/*======================================================*/ + +static ssize_t tcs3490_chip_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tcs3490_chip *chip = dev_get_drvdata(dev); + uint8_t id; + + tcs3490_i2c_read(chip, TCS3490_CHIPID, &id); + chip->shadow[TCS3490_CHIPID] = id; + + return snprintf(buf, + PAGE_SIZE, + "0x%02x", + chip->shadow[TCS3490_CHIPID]); +} + +static ssize_t tcs3490_notify(struct device *dev, + struct device_attribute *attr, char *buf) +{ + dev_dbg(dev, "%s: Notify is called", __func__); + return snprintf(buf, PAGE_SIZE, "%d", 1); +} + +/*=========== DEFINE DEVICE_ATTR ==================*/ +static DEVICE_ATTR(chip_pow, S_IRUGO | S_IWUSR | S_IWGRP, + tcs3490_chip_pow_show, tcs3490_chip_pow_store); +static DEVICE_ATTR(als_Itime, S_IRUGO | S_IWUSR | S_IWGRP, + tcs3490_als_itime_show, tcs3490_als_itime_store); +static DEVICE_ATTR(als_thres, S_IRUGO | S_IWUSR | S_IWGRP, + tcs3490_als_thres_show, tcs3490_als_thres_store); +static DEVICE_ATTR(als_red, S_IRUGO, tcs3490_als_red_show, NULL); +static DEVICE_ATTR(als_green, S_IRUGO, tcs3490_als_green_show, NULL); +static DEVICE_ATTR(als_blue, S_IRUGO, tcs3490_als_blue_show, NULL); +static DEVICE_ATTR(als_clear, S_IRUGO, tcs3490_als_clear_show, NULL); +static DEVICE_ATTR(als_all, S_IRUGO, tcs3490_als_all_show, NULL); +static DEVICE_ATTR(als_gain, S_IRUGO | S_IWUSR | S_IWGRP, + tcs3490_als_gain_show, tcs3490_als_gain_store); +static DEVICE_ATTR(als_thresh_deltaP, S_IRUGO | S_IWUSR | S_IWGRP, + tcs3490_als_deltaP_show, tcs3490_als_deltaP_store); +static DEVICE_ATTR(als_auto_gain, S_IRUGO | S_IWUSR | S_IWGRP, + tcs3490_auto_gain_enable_show, + tcs3490_auto_gain_enable_store); +static DEVICE_ATTR(als_power_state, S_IRUGO | S_IWUSR | S_IWGRP, + tcs3490_als_enable_show, tcs3490_als_enable_store); +static DEVICE_ATTR(als_persist, S_IRUGO | S_IWUSR | S_IWGRP, + tcs3490_als_persist_show, tcs3490_als_persist_store); +static DEVICE_ATTR(als_channel, S_IRUGO | S_IWUSR | S_IWGRP, + tcs3490_als_channel_show, tcs3490_als_channel_store); +static DEVICE_ATTR(chip_id, S_IRUGO, tcs3490_chip_id_show, NULL); +static DEVICE_ATTR(notify, S_IRUGO, tcs3490_notify, NULL); + +static struct attribute *tcs3490_attributes[] = { + &dev_attr_chip_pow.attr, + &dev_attr_als_Itime.attr, + &dev_attr_als_thres.attr, + &dev_attr_als_red.attr, + &dev_attr_als_green.attr, + &dev_attr_als_blue.attr, + &dev_attr_als_clear.attr, + &dev_attr_als_all.attr, + &dev_attr_als_gain.attr, + &dev_attr_als_thresh_deltaP.attr, + &dev_attr_als_auto_gain.attr, + &dev_attr_als_power_state.attr, + &dev_attr_als_persist.attr, + &dev_attr_als_channel.attr, + &dev_attr_chip_id.attr, + &dev_attr_notify.attr, + NULL +}; + +static const struct attribute_group tcs3490_attr_group = { + .attrs = tcs3490_attributes, +}; + +static int tcs3490_sensor_cam_io_notifier_call(struct notifier_block *self, + unsigned long event, void *data) +{ + struct tcs3490_chip *chip; + uint32_t rc; + + if (event & REGULATOR_EVENT_DISABLE) { + chip = container_of(self, struct tcs3490_chip, cam_io_regulator_cb); + dev_info(&chip->client->dev, + "%s REGULATOR_EVENT_DISABLE occurred event \n", __func__); + if (chip->vdd_supply_enable) + rc = regulator_disable(chip->vdd); + else if (chip->gpio_vdd_enable) + rc = regulator_disable(chip->gpio_vdd); + if (!rc) { + chip->unpowered = true; + dev_info(&chip->client->dev, + "%s: Regulator vdd disable OK", __func__); + } else { + dev_err(&chip->client->dev, + "%s: Regulator vdd disable failed", __func__); + } + } + return NOTIFY_OK; +} + +static int tcs3490_pltf_power_on(struct tcs3490_chip *chip) +{ + int rc = 0; + + mutex_lock(&chip->lock); + if (chip->vdd_supply_enable) + rc = regulator_enable(chip->vdd); + else if (chip->gpio_vdd_enable) + rc = regulator_enable(chip->gpio_vdd); + if (rc) { + dev_err(&chip->client->dev, + "Regulator vdd enable failed rc=%d\n", rc); + chip->unpowered = true; + mutex_unlock(&chip->lock); + } else { + if (chip->is_register_regulator_cam_vio_notify) { + regulator_unregister_notifier(chip->vio, + &(chip->cam_io_regulator_cb)); + chip->is_register_regulator_cam_vio_notify = false; + } + if (chip->vio_supply_enable) + rc = regulator_enable(chip->vio); + if (rc) { + dev_err(&chip->client->dev, + "%s: Regulator vio enable failed rc=%d\n", __func__, rc); + chip->unpowered = true; + mutex_unlock(&chip->lock); + } + } + if (!rc) { + dev_dbg(&chip->client->dev, + "%s: rgbcir, power init, regulator enable OK\n", __func__); + + /* Enable Oscillator */ + usleep_range(1000, 1000); + tcs3490_i2c_write(chip, TCS3490_CONTROL, 0x01); + mutex_unlock(&chip->lock); + usleep_range(10000, 11000); + } + return rc; +} + +static int tcs3490_power_on(struct tcs3490_chip *chip) +{ + int rc = 0; + + rc = tcs3490_pltf_power_on(chip); + if (rc) + return rc; + dev_info(&chip->client->dev, "%s: chip was off, restoring regs\n", + __func__); + + dev_info(&chip->client->dev, "tcs3490: Setting defaults\n"); + tcs3490_set_defaults(chip); + rc = tcs3490_flush_regs(chip); + + if (!rc) { + chip->unpowered = false; + } else { + tcs3490_pltf_power_off(chip); + } + + return rc; +} + +static int tcs3490_pltf_power_off(struct tcs3490_chip *chip) +{ + int rc = 0; + int rc2 = 0; + + mutex_lock(&chip->lock); + /* Disable Oscillator */ + tcs3490_i2c_write(chip, TCS3490_CONTROL, 0x00); + usleep_range(3000, 4000); + if (chip->vio_supply_enable && !chip->is_register_regulator_cam_vio_notify) { + chip->cam_io_regulator_cb.notifier_call = tcs3490_sensor_cam_io_notifier_call; + chip->cam_io_regulator_cb.priority = RGBCIR_SENSOR_REGULATOR_NOTIFY_PRIORITY; + if (regulator_register_notifier(chip->vio, &(chip->cam_io_regulator_cb))) + dev_err(&chip->client->dev, + "%s Regulator notification registration failed!\n", __func__); + else + chip->is_register_regulator_cam_vio_notify = true; + } + if (chip->vio_supply_enable) { + rc2 = regulator_disable(chip->vio); + if (rc2) + dev_err(&chip->client->dev, + "%s: Regulator vio disable failed", __func__); + else + dev_info(&chip->client->dev, + "%s: Regulator vio disable OK", __func__); + } + if (!chip->is_register_regulator_cam_vio_notify) { + if (chip->vdd_supply_enable) + rc = regulator_disable(chip->vdd); + else if (chip->gpio_vdd_enable) + rc = regulator_disable(chip->gpio_vdd); + + if (!rc && !rc2) + chip->unpowered = true; + } + mutex_unlock(&chip->lock); + return rc; +} + + +static int tcs3490_power_init(struct tcs3490_chip *chip) +{ + int rc = 0; + if (!chip) + return -EINVAL; + chip->unpowered = true; + if (chip->vdd_supply_enable) { + chip->vdd = regulator_get(&chip->client->dev, "rgbcir_vdd"); + if (IS_ERR(chip->vdd)) { + rc = PTR_ERR(chip->vdd); + dev_err(&chip->client->dev, + "Regulator get failed, vdd, rc = %d\n", rc); + return rc; + } + } else if (chip->gpio_vdd_enable) { + chip->gpio_vdd = regulator_get(&chip->client->dev, "rgbcir-gpio-vdd"); + if (IS_ERR(chip->gpio_vdd)) { + rc = PTR_ERR(chip->gpio_vdd); + dev_err(&chip->client->dev, + "Gpio-Regulator get failed,gpio_vdd, rc = %d\n", rc); + return rc; + } + } + if (chip->vio_supply_enable) { + chip->vio = regulator_get(&chip->client->dev, "rgbcir-vio"); + if (IS_ERR(chip->vio)) { + rc = PTR_ERR(chip->vio); + dev_err(&chip->client->dev, + "%s: Regulator get failed,vio, rc = %d\n", __func__, rc); + return rc; + } + } + chip->is_register_regulator_cam_vio_notify = false; + dev_info(&chip->client->dev, + "%s: rgbcir, power init, regulator get OK vdd=%d, gpio_vdd=%d, vio=%d\n", __func__, chip->vdd_supply_enable, chip->gpio_vdd_enable, chip->vio_supply_enable); + return rc; +} + +static int tcs3490_power_deinit(struct tcs3490_chip *chip) +{ + int rc = 0; + if (!chip) + return -EINVAL; + chip->unpowered = true; + if (chip->vio_supply_enable && chip->vio) { + regulator_put(chip->vio); + } + if (chip->is_register_regulator_cam_vio_notify) { + regulator_unregister_notifier(chip->vio, &(chip->cam_io_regulator_cb)); + chip->is_register_regulator_cam_vio_notify = false; + } + if (chip->vdd_supply_enable && chip->vdd) { + regulator_put(chip->vdd); + } else if (chip->gpio_vdd_enable && chip->gpio_vdd) { + regulator_put(chip->gpio_vdd); + } + return rc; +} + +static int tcs3490_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tcs3490_chip *chip; + int rc = 0; + uint32_t val_u32; + + dev_info(&client->dev, "start probing tcs3490\n"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, + "%s: check functionality failed", __func__); + return -EIO; + } + dev_info(&client->dev, "tcs3490: Checking IRQ number %d\n", + client->irq); + if (client->irq < 0) { + dev_err(&client->dev, "%s: no reason to run.\n", __func__); + rc = -EINVAL; + goto init_failed; + } else { + dev_info(&client->dev, "%s: client->irq = %d\n", + __func__, client->irq); + } + chip = kzalloc(sizeof(struct tcs3490_chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + i2c_set_clientdata(client, chip); + chip->client = client; + chip->device_index = 0; /*use default*/ + if (chip->client->dev.of_node) { + rc = tcs3490_pinctrl_init(chip); + if (rc) { + dev_err(&client->dev, + "%s: failed to pinctrl init\n", __func__); + goto pinctrl_init_failed; + } + } + + dev_info(&chip->client->dev, "tcs3490: Initializing mutex\n"); + mutex_init(&chip->lock); + + rc = of_property_read_u32(client->dev.of_node, + "ams,rgbcir-vdd-supply", &val_u32); + if (rc < 0) { + dev_err(&client->dev, "%s failed %d\n", __func__, __LINE__); + goto pinctrl_init_failed; + } + chip->vdd_supply_enable = val_u32; + + rc = of_property_read_u32(client->dev.of_node, + "ams,rgbcir-gpio-vdd", &val_u32); + if (rc < 0) { + dev_err(&client->dev, "%s failed %d\n", __func__, __LINE__); + goto pinctrl_init_failed; + } + chip->gpio_vdd_enable = val_u32; + + rc = of_property_read_u32(client->dev.of_node, + "ams,rgbcir-vio-supply", &val_u32); + if (rc < 0) { + dev_err(&client->dev, "%s failed %d\n", __func__, __LINE__); + goto pinctrl_init_failed; + } + chip->vio_supply_enable = val_u32; + + rc = tcs3490_power_init(chip); + if (rc) + goto pinctrl_init_failed; + + chip->a_idev = input_allocate_device(); + if (!chip->a_idev) { + rc = -ENOMEM; + dev_err(&client->dev, + "%s: failed to allocate input device", __func__); + goto allocate_device_failed; + } + chip->a_idev->name = "AMS TCS3490 Sensor"; + + dev_info(&chip->client->dev, "tcs3490: set bit EV_ABS\n"); + set_bit(EV_ABS, chip->a_idev->evbit); + + dev_info(&chip->client->dev, "tcs3490: set bit ABS_MISC\n"); + set_bit(ABS_MISC, chip->a_idev->absbit); + + dev_info(&chip->client->dev, "tcs3490: Set ABS params\n"); + input_set_abs_params(chip->a_idev, ABS_MISC, 0, 65535, 0, 0); /*check*/ + + dev_info(&chip->client->dev, + "tcs3490: assigning open/close functions\n"); + + rc = input_register_device(chip->a_idev); + if (rc) { + dev_err(&client->dev, + "failed to register input device"); + goto register_device_failed; + } + input_set_drvdata(chip->a_idev, chip); + dev_info(&chip->client->dev, "tcs3490: i2c nr %d\n", + client->adapter->nr); + + rc = sysfs_create_group(&chip->a_idev->dev.kobj, + &tcs3490_attr_group); + if (rc) { + rc = -ENOMEM; + dev_err(&client->dev, + "%s: failed to create sysfs group", __func__); + goto create_group_failed; + } + + rc = sysfs_create_link(chip->a_idev->dev.kobj.parent, + &chip->a_idev->dev.kobj, RGBCIR_SENSOR_SYSFS_LINK_NAME); + if (rc) { + rc = -ENOMEM; + dev_err(&client->dev, + "%s: failed to create sysfs link", __func__); + goto create_link_failed; + } + + dev_info(&client->dev, "Probe ok.\n"); + return 0; + +create_link_failed: + sysfs_remove_group(&chip->a_idev->dev.kobj, + &tcs3490_attr_group); +create_group_failed: + input_unregister_device(chip->a_idev); +register_device_failed: + input_free_device(chip->a_idev); +allocate_device_failed: + tcs3490_power_deinit(chip); +pinctrl_init_failed: + kfree(chip); +init_failed: + dev_err(&client->dev, "Probe failed.\n"); + return rc; +} + +static int tcs3490_remove(struct i2c_client *client) +{ + struct tcs3490_chip *chip = i2c_get_clientdata(client); + sysfs_remove_link(&chip->a_idev->dev.kobj, + RGBCIR_SENSOR_SYSFS_LINK_NAME); + sysfs_remove_group(&chip->a_idev->dev.kobj, + &tcs3490_attr_group); + free_irq(client->irq, chip); + if (chip->a_idev) { + input_unregister_device(chip->a_idev); + } + + i2c_set_clientdata(client, NULL); + kfree(chip); + return 0; +} + +static const struct i2c_device_id tcs3490_idtable[] = { + { "tcs3490", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, tcs3490_idtable); + +static const struct of_device_id tcs3490_dt_match[] = { + { .compatible = "ams,tcs3490", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tcs3490_dt_match); + +static struct i2c_driver tcs3490_driver = { + .driver = { + .name = "tcs3490", + .owner = THIS_MODULE, + .of_match_table = tcs3490_dt_match, + }, + .id_table = tcs3490_idtable, + .probe = tcs3490_probe, + .remove = tcs3490_remove, +}; + +static int __init tcs3490_init(void) +{ + int rc = 0; + + pr_info("Initialize TCS3490 driver"); + rc = i2c_add_driver(&tcs3490_driver); + pr_info("TCS3490 added i2c driver rc = %d", rc); + + return rc; +} + +static void __exit tcs3490_exit(void) +{ + pr_info("Delete TCS3490 driver"); + i2c_del_driver(&tcs3490_driver); +} + +module_init(tcs3490_init); +module_exit(tcs3490_exit); + +MODULE_DESCRIPTION("AMS tcs3490 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/tcs3490.h b/drivers/misc/tcs3490.h new file mode 100644 index 0000000000000000000000000000000000000000..0c23ebdf8cdf49b3cd05f785cfcb9046b6684dcc --- /dev/null +++ b/drivers/misc/tcs3490.h @@ -0,0 +1,94 @@ +/* + * Device driver for monitoring ambient light intensity in (lux), RGB, and + * color temperature (in kelvin) within the AMS-TAOS TCS family of devices. + * + * Copyright (c) 2016, AMS-TAOS USA, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __TCS3490_H +#define __TCS3490_H + +#include + +/* Max number of segments allowable in LUX table */ +#define TCS3490_MAX_LUX_TABLE_SIZE 9 +#define MAX_DEFAULT_TABLE_BYTES (sizeof(int) * TCS3490_MAX_LUX_TABLE_SIZE) + +/* Default LUX and Color coefficients */ + +#define D_Factor 304 +#define R_Coef 205 +#define G_Coef 1024 +#define B_Coef (-184) +#define CT_Coef (4659) +#define CT_Offset (1023) + +#define D_Factor1 304 +#define R_Coef1 205 +#define G_Coef1 1024 +#define B_Coef1 (-184) +#define CT_Coef1 (4659) +#define CT_Offset1 (1023) + +struct device; + +enum tcs3490_pwr_state { + POWER_ON, + POWER_OFF, + POWER_STANDBY, +}; + +enum tcs3490_ctrl_reg { + AGAIN_1 = (0 << 0), + AGAIN_4 = (1 << 0), + AGAIN_16 = (2 << 0), + AGAIN_64 = (3 << 0), +}; + +#define ALS_PERSIST(p) (((p) & 0xf) << 3) + +struct tcs3490_parameters { + u8 als_time; + u16 als_deltaP; + u8 als_gain; + u8 persist; +}; + +struct lux_segment { + int d_factor; + int r_coef; + int g_coef; + int b_coef; + int ct_coef; + int ct_offset; +}; + + +struct tcs3490_i2c_platform_data { + /* The following callback for power events received and handled by + the driver. Currently only for SUSPEND and RESUME */ + int (*platform_power)(struct device *dev, enum tcs3490_pwr_state state); + int (*platform_init)(void); + void (*platform_teardown)(struct device *dev); + char const *als_name; + struct tcs3490_parameters parameters; + bool als_can_wake; + struct lux_segment *segment; + int segment_num; +}; + +#endif /* __TCS3490_H */ diff --git a/drivers/misc/tof_sensor.c b/drivers/misc/tof_sensor.c new file mode 100644 index 0000000000000000000000000000000000000000..9809c25d03fb686f96ffbed8f6204f38baab1178 --- /dev/null +++ b/drivers/misc/tof_sensor.c @@ -0,0 +1,646 @@ +/* + * Tof sensor driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define ENABLE_LOGE + +#ifdef ENABLE_LOGE +#define LOGE(dev, f, a...) dev_err(dev, "%s: " f, __func__, ##a) +#else +#define LOGE(dev, f, a...) +#endif + +#ifdef ENABLE_LOGI +#define LOGI(dev, f, a...) dev_info(dev, "%s: " f, __func__, ##a) +#else +#define LOGI(dev, f, a...) +#endif + +#ifdef ENABLE_LOGD +#define LOGD(dev, f, a...) dev_dbg(dev, "%s: " f, __func__, ##a) +#else +#define LOGD(dev, f, a...) +#endif + +#define TOF_SENSOR_SYSFS_LINK_NAME "tof_sensor" +#define TOF_SENSOR_PINCTRL_IRQ_ACTIVE "tof_irq_active" +#define TOF_SENSOR_PINCTRL_IRQ_SUSPEND "tof_irq_suspend" +#define TOF_SENSOR_REGULATOR_NOTIFY_PRIORITY (1000) + +struct tof_sensor_info { + char name[8]; + uint32_t i2c_client_id; + uint32_t need_camera_on; + uint32_t facing; + uint32_t vdd_supply_enable; + uint32_t gpio_avdd_enable; +}; + +struct tof_sensor_data { + struct i2c_client *client; + struct regulator *avdd; + struct regulator *gpio_avdd; + uint32_t min_voltage; + uint32_t max_voltage; + uint8_t power_up; + bool is_avdd_enabled; + bool is_register_regulator_cam_vio_notify; + struct input_dev *input; + const char *dev_name; + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + struct tof_sensor_info info; + struct notifier_block cam_io_regulator_cb; + int tof_reset_gpio; + uint32_t ref_cnt; +}; + +static int tof_sensor_cam_io_notifier_call(struct notifier_block *self, + unsigned long event, void *data) +{ + struct tof_sensor_data *tof_data; + uint32_t rc; + + if (event & REGULATOR_EVENT_DISABLE) { + tof_data = container_of(self, struct tof_sensor_data, + cam_io_regulator_cb); + LOGD(&tof_data->client->dev, + "%s REGULATOR_EVENT_DISABLE occurred event \n", __func__); + if (tof_data->is_avdd_enabled && tof_data->avdd) { + rc = regulator_disable(tof_data->avdd); + tof_data->is_avdd_enabled = false; + if (!rc) + LOGD(&tof_data->client->dev, + "%s: Regulator avdd disable OK", + __func__); + else + LOGE(&tof_data->client->dev, + "%s: Regulator avdd disable failed ", + __func__); + } + } + return NOTIFY_OK; +} + +static int tof_sensor_power_init(struct tof_sensor_data *data) +{ + int rc = 0; + + if ((data->avdd == NULL) && data->info.vdd_supply_enable) { + data->avdd = regulator_get(&data->client->dev, "tof_avdd"); + if (IS_ERR(data->avdd)) { + rc = PTR_ERR(data->avdd); + LOGE(&data->client->dev, + "Regulator get failed, avdd, rc = %d\n", rc); + return rc; + } + } + if ((data->gpio_avdd == NULL) && data->info.gpio_avdd_enable) { + data->gpio_avdd = regulator_get(&data->client->dev, "tof-gpio-avdd"); + if (IS_ERR(data->gpio_avdd)) { + rc = PTR_ERR(data->gpio_avdd); + LOGE(&data->client->dev, + "Regulator get failed, avdd, rc = %d\n", rc); + return rc; + } + } + data->is_avdd_enabled = false; + data->is_register_regulator_cam_vio_notify = false; + LOGI(&data->client->dev, "%s: power init, regulator get OK", + __func__); + return rc; +} + +static int tof_sensor_power_deinit(struct tof_sensor_data *data) +{ + int rc = 0; + if (!data) + return -EINVAL; + if (data->info.vdd_supply_enable && data->avdd) + regulator_put(data->avdd); + if (data->is_register_regulator_cam_vio_notify) { + regulator_unregister_notifier(data->gpio_avdd, &(data->cam_io_regulator_cb)); + data->is_register_regulator_cam_vio_notify = false; + } + if (data->info.gpio_avdd_enable && data->gpio_avdd) + regulator_put(data->gpio_avdd); + return rc; +} + +static int tof_sensor_pinctrl_init(struct tof_sensor_data *data) +{ + + data->pinctrl = devm_pinctrl_get(&data->client->dev); + if (IS_ERR_OR_NULL(data->pinctrl)) { + LOGE(&data->client->dev, + "%s:%d Getting pinctrl handle failed\n", + __func__, __LINE__); + return -EINVAL; + } + data->gpio_state_active = + pinctrl_lookup_state(data->pinctrl, + TOF_SENSOR_PINCTRL_IRQ_ACTIVE); + if (IS_ERR_OR_NULL(data->gpio_state_active)) { + LOGE(&data->client->dev, + "%s:Failed to get the active state pinctrl handle\n", + __func__); + return -EINVAL; + } + data->gpio_state_suspend + = pinctrl_lookup_state(data->pinctrl, + TOF_SENSOR_PINCTRL_IRQ_SUSPEND); + if (IS_ERR_OR_NULL(data->gpio_state_suspend)) { + LOGE(&data->client->dev, + "%s:Failed to get the suspend state pinctrl handle\n", + __func__); + return -EINVAL; + } + return 0; +} + +static int tof_sensor_gpio_init(struct tof_sensor_data *data) +{ + int rc = 0; + int flag = 0; + + rc = gpio_request_one(data->tof_reset_gpio, flag, "tof-reset-gpio"); + if (rc) { + LOGE(&data->client->dev, + "%s:%d Getting reset gpio failed\n", + __func__, __LINE__); + return -EINVAL; + } else { + return 0; + } +} + +static int tof_sensor_parse_dt(struct tof_sensor_data *data) +{ + int rc = 0; + const char *name = NULL; + uint32_t val_u32 = 0; + + rc = of_property_read_string_index(data->client->dev.of_node, + "sony,tof-sensor-name", 0, (const char **)(&name)); + if (rc < 0) { + LOGE(&data->client->dev, "%s failed %d\n", __func__, __LINE__); + goto fail; + } + memcpy(data->info.name, name, 8); + + rc = of_property_read_u32(data->client->dev.of_node, + "sony,tof-need-cam-on", &val_u32); + if (rc < 0) { + LOGE(&data->client->dev, "%s failed %d\n", __func__, __LINE__); + goto fail; + } + data->info.need_camera_on = val_u32; + + rc = of_property_read_u32(data->client->dev.of_node, + "sony,tof-sensor-facing", &val_u32); + if (rc < 0) { + LOGE(&data->client->dev, "%s failed %d\n", __func__, __LINE__); + goto fail; + } + data->info.facing = val_u32; + + data->tof_reset_gpio = of_get_named_gpio(data->client->dev.of_node, + "tof-reset-gpio", 0); + + rc = of_property_read_u32(data->client->dev.of_node, + "sony,tof-avdd-supply", &val_u32); + if (rc < 0) { + LOGE(&data->client->dev, "%s failed %d\n", __func__, __LINE__); + goto fail; + } + data->info.vdd_supply_enable = val_u32; + + rc = of_property_read_u32(data->client->dev.of_node, + "sony,tof-gpio-avdd", &val_u32); + if (rc < 0) { + LOGE(&data->client->dev, "%s failed %d\n", __func__, __LINE__); + goto fail; + } + data->info.gpio_avdd_enable = val_u32; + + + LOGD(&data->client->dev, "%s name %s, need_camera_on %d, facing %d\n", + __func__, data->info.name, data->info.need_camera_on, + data->info.facing); + +fail: + return rc; +} + +static irqreturn_t tof_sensor_irq(int irq, void *handle) +{ + struct tof_sensor_data *data = handle; + + LOGI(&data->client->dev, "Tof sensor irq"); + sysfs_notify(&data->input->dev.kobj, NULL, "tof_ranging_notify"); + + return IRQ_HANDLED; +} + +static ssize_t tof_sensor_power_ctl(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tof_sensor_data *data = dev_get_drvdata(dev); + int rc = 0; + unsigned long value = 0; + + LOGD(&data->client->dev, + "%s: Power control data", __func__); + rc = kstrtoul(buf, sizeof(value), &value); + if (rc) { + LOGE(&data->client->dev, + "%s: covert error. rc = %d", __func__, rc); + return count; + } + if (value == TOF_SENSOR_POWER_CONTROL_ON) { + if (!data->ref_cnt) { + /* power on */ + if (!rc && + data->pinctrl && data->gpio_state_active) { + rc = pinctrl_select_state(data->pinctrl, + data->gpio_state_active); + if (rc) + LOGE(&data->client->dev, + "%s: cannot set pin to active state", + __func__); + } + if (!rc) { + rc = request_threaded_irq(data->client->irq, NULL, + &tof_sensor_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(&data->client->dev), data); + if (rc) { + LOGE(&data->client->dev, + "Failed to request irq %d\n", + data->client->irq); + (void)pinctrl_select_state(data->pinctrl, + data->gpio_state_suspend); + } + } + if (!rc && data->is_register_regulator_cam_vio_notify) { + regulator_unregister_notifier(data->gpio_avdd, + &(data->cam_io_regulator_cb)); + data->is_register_regulator_cam_vio_notify = false; + } + if (!rc && data->info.vdd_supply_enable) { + rc = regulator_enable(data->avdd); + if (rc) { + LOGE(&data->client->dev, + "Regulator avdd enable failed rc=%d", + rc); + pinctrl_select_state(data->pinctrl, + data->gpio_state_suspend); + free_irq(data->client->irq, data); + return count; + } + data->is_avdd_enabled = true; + usleep_range(3000, 4000); + } + if (!rc && data->info.gpio_avdd_enable) { + rc = regulator_enable(data->gpio_avdd); + if (rc) { + LOGE(&data->client->dev, + "Regulator gpio_avdd enable failed rc=%d", rc); + pinctrl_select_state(data->pinctrl, + data->gpio_state_suspend); + free_irq(data->client->irq, data); + return count; + } + } + if (!rc && data->info.need_camera_on) { + rc = gpio_direction_output(data->tof_reset_gpio, 1); + if (rc) { + LOGE(&data->client->dev, + "%s: reset enable failed", + __func__); + regulator_disable(data->avdd); + free_irq(data->client->irq, data); + pinctrl_select_state(data->pinctrl, + data->gpio_state_suspend); + return count; + } + LOGD(&data->client->dev, + "%s: power up regulator enable OK", + __func__); + usleep_range(3000, 4000); + data->power_up = 1; + } + } + data->ref_cnt++; + } else if (value == TOF_SENSOR_POWER_CONTROL_OFF) { + /* power off */ + if (data->ref_cnt > 0) { + data->ref_cnt--; + if (!data->ref_cnt) { + if (data->info.need_camera_on) { + rc = gpio_direction_output(data->tof_reset_gpio, 0); + if (rc) + LOGE(&data->client->dev, + "%s: reset disable failed", + __func__); + else { + data->power_up = 0; + LOGD(&data->client->dev, + "%s: reset disable ok", + __func__); + } + } + if (data->info.gpio_avdd_enable && data->info.vdd_supply_enable && + !data->is_register_regulator_cam_vio_notify) { + data->cam_io_regulator_cb.notifier_call = + tof_sensor_cam_io_notifier_call; + data->cam_io_regulator_cb.priority = + TOF_SENSOR_REGULATOR_NOTIFY_PRIORITY; + if (regulator_register_notifier(data->gpio_avdd, + &(data->cam_io_regulator_cb))) + LOGE(&data->client->dev, + "%s Regulator notification registration failed!\n", + __func__); + else + data->is_register_regulator_cam_vio_notify = true; + } + if (data->info.gpio_avdd_enable) { + rc = regulator_disable(data->gpio_avdd); + if (rc) { + LOGE(&data->client->dev, + "%s: Regulator gpio_avdd disable failed ", + __func__); + } else { + LOGE(&data->client->dev, + "%s: power up gpio_regulator disable OK", + __func__); + } + } + if (data->info.vdd_supply_enable) { + if (!data->is_register_regulator_cam_vio_notify) { + rc = regulator_disable(data->avdd); + data->is_avdd_enabled = 0; + if (!rc) + LOGD(&data->client->dev, + "%s: Regulator avdd disable OK", + __func__); + else + LOGE(&data->client->dev, + "%s: Regulator avdd disable failed ", + __func__); + } + } + free_irq(data->client->irq, data); + if (data->pinctrl && data->gpio_state_suspend) { + rc = pinctrl_select_state(data->pinctrl, + data->gpio_state_suspend); + if (rc) + LOGE(&data->client->dev, + "%s: cannot set pin to suspend state", + __func__); + } + } + } + } else + LOGE(&data->client->dev, + "%s: Power control data error [%ld]", __func__, + value); + + return count; +} + +static ssize_t tof_sensor_show_power_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tof_sensor_data *data = dev_get_drvdata(dev); + + LOGI(dev, "Get power stat is called"); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->power_up); +} + +static ssize_t tof_sensor_ranging_notify(struct device *dev, + struct device_attribute *attr, char *buf) +{ + LOGI(dev, "Ranging notify is called"); + + return snprintf(buf, PAGE_SIZE, "%d", 1); +} + +static ssize_t tof_sensor_get_info(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tof_sensor_data *data = dev_get_drvdata(dev); + + LOGI(dev, "Get information is called"); + + return snprintf(buf, PAGE_SIZE, "%s,%u,%u,%u", data->info.name, + data->info.i2c_client_id, data->info.need_camera_on, + data->info.facing); +} + +static DEVICE_ATTR(tof_get_info, S_IRUGO, tof_sensor_get_info, NULL); +static DEVICE_ATTR(tof_ranging_notify, S_IRUGO, tof_sensor_ranging_notify, + NULL); +static DEVICE_ATTR(tof_power_ctl, S_IRUGO | S_IWUSR | S_IWGRP, + tof_sensor_show_power_status, tof_sensor_power_ctl); +static struct attribute *tof_sensor_attributes[] = { + &dev_attr_tof_get_info.attr, + &dev_attr_tof_ranging_notify.attr, + &dev_attr_tof_power_ctl.attr, + NULL +}; + +static const struct attribute_group tof_sensor_attr_group = { + .attrs = tof_sensor_attributes, +}; + +static int tof_sensor_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tof_sensor_data *data; + int rc = 0; + + LOGI(&client->dev, "start probing stmdata\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + LOGE(&client->dev, + "%s: check_functionality failed.", __func__); + return -EIO; + } + + data = kzalloc(sizeof(struct tof_sensor_data), GFP_KERNEL); + if (!data) { + LOGE(&client->dev, "failed: no memory to alloc data %p", data); + return -ENOMEM; + } + + i2c_set_clientdata(client, data); + data->client = client; + if (data->client->dev.of_node) { + rc = tof_sensor_pinctrl_init(data); + if (rc) { + LOGE(&client->dev, + "%s: failed to pinctrl init", __func__); + goto exit_free_i2c; + } + rc = tof_sensor_parse_dt(data); + if (rc) { + LOGE(&client->dev, + "%s: failed to parse dt", __func__); + goto exit_free_i2c; + } + } + rc = tof_sensor_power_init(data); + if (rc) { + LOGE(&client->dev, + "%s: failed to power init", __func__); + goto exit_free_i2c; + } + tof_sensor_gpio_init(data); + data->ref_cnt = 0; + + data->dev_name = dev_name(&client->dev); + data->input = input_allocate_device(); + if (!data->input) { + rc = -ENOMEM; + LOGE(&client->dev, + "%s: failed to allocate input device", __func__); + goto exit_free_i2c; + } + data->input->name = "ToF Sensor"; + rc = input_register_device(data->input); + if (rc) { + LOGE(&client->dev, "Failed to register input device"); + goto exit_free_dev; + } + input_set_drvdata(data->input, data); + + LOGI(&client->dev, "tof sensor: i2c nr%d\n", client->adapter->nr); + data->info.i2c_client_id = client->adapter->nr; + data->power_up = 0; + + /* sysfs */ + rc = sysfs_create_group(&data->input->dev.kobj, + &tof_sensor_attr_group); + if (rc) { + rc = -ENOMEM; + LOGE(&client->dev, + "%s: failed to create sysfs group", __func__); + goto exit_unregister_sysfs; + } + + rc = sysfs_create_link(data->input->dev.kobj.parent, + &data->input->dev.kobj, + TOF_SENSOR_SYSFS_LINK_NAME); + if (rc) { + rc = -ENOMEM; + LOGE(&client->dev, + "%s: failed to create sysfs link", __func__); + goto exit_unregister_sysfs; + } + return rc; + +exit_unregister_sysfs: + input_unregister_device(data->input); +exit_free_dev: + input_free_device(data->input); +exit_free_i2c: + tof_sensor_power_deinit(data); + i2c_set_clientdata(data->client, NULL); + kfree(data); + + return rc; +} + +static int tof_sensor_remove(struct i2c_client *client) +{ + struct tof_sensor_data *data = i2c_get_clientdata(client); + + gpio_free(data->tof_reset_gpio); + tof_sensor_power_deinit(data); + sysfs_remove_link(&data->input->dev.kobj, + TOF_SENSOR_SYSFS_LINK_NAME); + input_unregister_device(data->input); + input_free_device(data->input); + LOGI(&data->client->dev, "Removed."); + i2c_set_clientdata(data->client, NULL); + kfree(data); + + return 0; +} + +static struct i2c_device_id tof_sensor_id[] = { + { "tof_sensor", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, tof_sensor_id); + +static struct of_device_id st_tof_sensor_dt_match[] = { + { .compatible = "tof_sensor", }, + { }, +}; + +static struct i2c_driver tof_sensor_i2c_driver = { + .driver = { + .name = "tof_sensor", + .owner = THIS_MODULE, + .of_match_table = st_tof_sensor_dt_match, + }, + .probe = tof_sensor_probe, + .remove = tof_sensor_remove, + .id_table = tof_sensor_id, +}; + +static int __init tof_sensor_init(void) +{ + int rc = 0; + + pr_info("%s: Initialize i2c driver", __func__); + rc = i2c_add_driver(&tof_sensor_i2c_driver); + pr_info("%s: Added i2c driver rc = %d", __func__, rc); + + return rc; +} + +static void __exit tof_sensor_exit(void) +{ + pr_info("Delete i2c driver"); + i2c_del_driver(&tof_sensor_i2c_driver); +} + +module_init(tof_sensor_init); +module_exit(tof_sensor_exit); + +MODULE_DESCRIPTION("Tof sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/uid_stat.c b/drivers/misc/uid_stat.c new file mode 100644 index 0000000000000000000000000000000000000000..fa5f8ab1d744d7ee50995bad584b2bdda7ad3d6b --- /dev/null +++ b/drivers/misc/uid_stat.c @@ -0,0 +1,158 @@ +/* drivers/misc/uid_stat.c + * + * Copyright (C) 2008 - 2009 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. + * + */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_SPINLOCK(uid_lock); +static LIST_HEAD(uid_list); +static struct proc_dir_entry *parent; + +struct uid_stat { + struct list_head link; + uid_t uid; + atomic_t tcp_rcv; + atomic_t tcp_snd; +}; + +static struct uid_stat *find_uid_stat(uid_t uid) { + struct uid_stat *entry; + + list_for_each_entry(entry, &uid_list, link) { + if (entry->uid == uid) { + return entry; + } + } + return NULL; +} + +static int uid_stat_atomic_int_show(struct seq_file *m, void *v) +{ + unsigned int bytes; + atomic_t *counter = m->private; + + bytes = (unsigned int) (atomic_read(counter) + INT_MIN); + seq_printf(m, "%u\n", bytes); + return 0; +} + +static int uid_stat_read_atomic_int_open(struct inode *inode, struct file *file) +{ + return single_open(file, uid_stat_atomic_int_show, PDE_DATA(inode)); +} + +static const struct file_operations uid_stat_read_atomic_int_fops = { + .open = uid_stat_read_atomic_int_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* Create a new entry for tracking the specified uid. */ +static struct uid_stat *create_stat(uid_t uid) { + struct uid_stat *new_uid; + /* Create the uid stat struct and append it to the list. */ + new_uid = kmalloc(sizeof(struct uid_stat), GFP_ATOMIC); + if (!new_uid) + return NULL; + + new_uid->uid = uid; + /* Counters start at INT_MIN, so we can track 4GB of network traffic. */ + atomic_set(&new_uid->tcp_rcv, INT_MIN); + atomic_set(&new_uid->tcp_snd, INT_MIN); + + list_add_tail(&new_uid->link, &uid_list); + return new_uid; +} + +static void create_stat_proc(struct uid_stat *new_uid) +{ + char uid_s[32]; + struct proc_dir_entry *entry; + sprintf(uid_s, "%d", new_uid->uid); + entry = proc_mkdir(uid_s, parent); + + /* Keep reference to uid_stat so we know what uid to read stats from. */ + proc_create_data("tcp_snd", S_IRUGO, entry, + &uid_stat_read_atomic_int_fops, &new_uid->tcp_snd); + + proc_create_data("tcp_rcv", S_IRUGO, entry, + &uid_stat_read_atomic_int_fops, &new_uid->tcp_rcv); +} + +static struct uid_stat *find_or_create_uid_stat(uid_t uid) +{ + struct uid_stat *entry; + unsigned long flags; + spin_lock_irqsave(&uid_lock, flags); + entry = find_uid_stat(uid); + if (entry) { + spin_unlock_irqrestore(&uid_lock, flags); + return entry; + } + entry = create_stat(uid); + spin_unlock_irqrestore(&uid_lock, flags); + if (entry) + create_stat_proc(entry); + return entry; +} + +int uid_stat_tcp_snd(uid_t uid, int size) { + struct uid_stat *entry; + activity_stats_update(); + entry = find_or_create_uid_stat(uid); + if (!entry) + return -1; + atomic_add(size, &entry->tcp_snd); + return 0; +} + +int uid_stat_tcp_rcv(uid_t uid, int size) { + struct uid_stat *entry; + activity_stats_update(); + entry = find_or_create_uid_stat(uid); + if (!entry) + return -1; + atomic_add(size, &entry->tcp_rcv); + return 0; +} + +static int __init uid_stat_init(void) +{ + parent = proc_mkdir("uid_stat", NULL); + if (!parent) { + pr_err("uid_stat: failed to create proc entry\n"); + return -1; + } + return 0; +} + +__initcall(uid_stat_init); diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index eeacaae492223c3a6c91e8d893fc420f6c7a3a91..d4249c733d66a24c36d5db23e8fbd3427ed08498 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -17,6 +17,11 @@ * Author: Andrew Christian * 28 May 2002 */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -1173,7 +1178,7 @@ idata_free: cmd_done: mmc_blk_put(md); - if (card && card->cmdq_init) + if (card->cmdq_init) wake_up(&card->host->cmdq_ctx.wait); return err; } @@ -1224,16 +1229,16 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ioc_err = __mmc_blk_ioctl_cmd(card, md, idata); + mmc_put_card(card); + + err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); + if (mmc_card_cmdq(card)) { if (mmc_cmdq_halt(card->host, false)) pr_err("%s: %s: cmdq unhalt failed\n", mmc_hostname(card->host), __func__); } - mmc_put_card(card); - - err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); - cmd_done: mmc_blk_put(md); cmd_err: @@ -1511,12 +1516,19 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries) return err; } +#define EXE_ERRORS \ + (R1_OUT_OF_RANGE | /* Command argument out of range */ \ + R1_ADDRESS_ERROR | /* Misaligned address */ \ + R1_WP_VIOLATION | /* Tried to write to protected block */ \ + R1_CARD_ECC_FAILED | /* ECC error */ \ + R1_ERROR) /* General/unknown error */ + static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, bool hw_busy_detect, struct request *req, int *gen_err) { unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); int err = 0; - u32 status; + u32 status, first_status = 0; do { err = get_card_status(card, &status, 5); @@ -1526,6 +1538,9 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, return err; } + if (!first_status) + first_status = status; + if (status & R1_ERROR) { pr_err("%s: %s: error sending status cmd, status %#x\n", req->rq_disk->disk_name, __func__, status); @@ -1556,6 +1571,14 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, } while (!(status & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(status) == R1_STATE_PRG)); + /* Check for errors during cmd execution. In this case + * the execution was terminated. */ + if (first_status & EXE_ERRORS) { + pr_err("%s: error during r/w command, err status %#x, status %#x\n", + req->rq_disk->disk_name, first_status, status); + return MMC_BLK_ABORT; + } + return err; } @@ -2238,12 +2261,25 @@ static int mmc_blk_err_check(struct mmc_card *card, return MMC_BLK_ABORT; } + /* Check execution mode errors. If stop cmd was sent, these + * errors would be reported in response to it. In this case + * the execution is retried using single-block read. */ + if (brq->stop.resp[0] & EXE_ERRORS) { + pr_err("%s: error during r/w command, stop response %#x\n", + req->rq_disk->disk_name, brq->stop.resp[0]); + return MMC_BLK_RETRY_SINGLE; + } + /* * Everything else is either success, or a data error of some * kind. If it was a write, we may have transitioned to * program mode, which we have to wait for it to complete. + * If pre defined block count (CMD23) was used, no stop + * cmd was sent and we need to read status to check + * for errors during cmd execution. */ - if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { + if (!mmc_host_is_spi(card->host) && + (rq_data_dir(req) != READ || brq->sbc.opcode == MMC_SET_BLOCK_COUNT)) { int err; /* Check stop command response */ @@ -3805,6 +3841,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) break; goto cmd_abort; } + case MMC_BLK_RETRY_SINGLE: case MMC_BLK_ECC_ERR: if (brq->data.blocks > 1) { /* Redo read one sector at a time */ @@ -4626,7 +4663,6 @@ static int mmc_blk_probe(struct mmc_card *card) #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME mmc_set_bus_resume_policy(card->host, 1); #endif - if (mmc_add_disk(md)) goto out; @@ -4636,7 +4672,13 @@ static int mmc_blk_probe(struct mmc_card *card) } pm_runtime_use_autosuspend(&card->dev); - pm_runtime_set_autosuspend_delay(&card->dev, MMC_AUTOSUSPEND_DELAY_MS); + + if (mmc_card_sd(card)) + pm_runtime_set_autosuspend_delay(&card->dev, + MMC_SDCARD_AUTOSUSPEND_DELAY_MS); + else + pm_runtime_set_autosuspend_delay(&card->dev, MMC_AUTOSUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&card->dev); /* diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 9e0ccdc44d6b1fccbdb9cd7d084a2652223d3b34..2b41b09667405eeddd087c7c23d18280836760ee 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -37,3 +37,19 @@ config MMC_CLKGATE support handling this in order for it to be of any use. If unsure, say N. + +config MMC_CMD_DEBUG + bool "Debug feature to get mmc command issued" + default n + help + This is a debug feature to get the mmc command issued + in order to debug certain issues from the logs. + +config MMC_CMD_QUEUE_SIZE + int "mmc command queue size" + depends on MMC_CMD_DEBUG + default 256 + help + Select the size of the circular queue to store the MMC command + issued. + diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 548a9e8b72aefee90aa165d75135de5dc02ae927..311f6d639d067ff9986bec66a8e9b6b94b66367b 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -401,7 +401,6 @@ int mmc_add_card(struct mmc_card *card) return ret; mmc_card_set_present(card); - device_enable_async_suspend(&card->dev); return 0; } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 372f1fbbde4cf17ac45bd43787dab9dd64c172aa..be6807d092b11dc7d74882a8b79c1d211d1306a5 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -10,6 +10,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -1088,6 +1093,24 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) if (mmc_card_removed(host->card)) return -ENOMEDIUM; +#ifdef CONFIG_MMC_CMD_DEBUG + if (host->card) { + struct mmc_cmdq *cq = NULL; + cq = &host->card->cmd_stats.cmdq[host->card-> + cmd_stats.next_idx]; + cq->opcode = mrq->cmd->opcode; + cq->arg = mrq->cmd->arg; + cq->flags = mrq->cmd->flags; + cq->timestamp = sched_clock(); + host->card->cmd_stats.next_idx++; + + if (host->card->cmd_stats.next_idx == CMD_QUEUE_SIZE) { + host->card->cmd_stats.next_idx = 0; + host->card->cmd_stats.wrapped = 1; + } + } +#endif + if (mrq->sbc) { pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", mmc_hostname(host), mrq->sbc->opcode, @@ -2992,7 +3015,10 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) host->card_clock_off = false; /* Wait for at least 1 ms according to spec */ - mmc_delay(1); + if (host->caps & MMC_CAP_NONREMOVABLE) + mmc_delay(1); + else + mmc_delay(40); /* * Failure to switch is indicated by the card holding @@ -3301,13 +3327,6 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay, pm_wakeup_event(mmc_dev(host), 5000); host->detect_change = 1; - /* - * Change in cd_gpio state, so make sure detection part is - * not overided because of manual resume. - */ - if (cd_irq && mmc_bus_manual_resume(host)) - host->ignore_bus_resume_flags = true; - mmc_schedule_delayed_work(&host->detect, delay); } @@ -4088,6 +4107,8 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) return 0; if (!mmc_attach_sd(host)) return 0; + else + mmc_gpio_tray_close_set_uim2(host, 1); if (!mmc_attach_mmc(host)) return 0; @@ -4172,18 +4193,6 @@ int mmc_detect_card_removed(struct mmc_host *host) } EXPORT_SYMBOL(mmc_detect_card_removed); -/* - * This should be called to make sure that detect work(mmc_rescan) - * is completed.Drivers may use this function from async schedule/probe - * contexts to make sure that the bootdevice detection is completed on - * completion of async_schedule. - */ -void mmc_flush_detect_work(struct mmc_host *host) -{ - flush_delayed_work(&host->detect); -} -EXPORT_SYMBOL(mmc_flush_detect_work); - void mmc_rescan(struct work_struct *work) { unsigned long flags; @@ -4218,8 +4227,6 @@ void mmc_rescan(struct work_struct *work) host->bus_ops->detect(host); host->detect_change = 0; - if (host->ignore_bus_resume_flags) - host->ignore_bus_resume_flags = false; /* * Let mmc_bus_put() free the bus/bus_ops if we've found that @@ -4289,6 +4296,8 @@ void mmc_stop_host(struct mmc_host *host) cancel_delayed_work_sync(&host->detect); mmc_flush_scheduled_work(); + mmc_gpio_set_uim2_en(host, 0); + /* clear pm flags now and let card drivers set them as needed */ host->pm_flags = 0; @@ -4452,6 +4461,9 @@ int mmc_pm_notify(struct notifier_block *notify_block, host->rescan_disable = 1; spin_unlock_irqrestore(&host->lock, flags); cancel_delayed_work_sync(&host->detect); +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME + mmc_cd_prepare_suspend(host); +#endif if (!host->bus_ops) break; @@ -4477,8 +4489,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 0; - if (mmc_bus_manual_resume(host) && - !host->ignore_bus_resume_flags) { + if (mmc_bus_manual_resume(host)) { spin_unlock_irqrestore(&host->lock, flags); break; } diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 72bfdd8351783258cf9414714a032763fbd5541c..3174c9fd6cee4f56c58aac8a4ff2dbfcb4c083a2 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -7,6 +7,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -845,6 +850,50 @@ static const struct file_operations mmc_dbg_bkops_stats_fops = { .write = mmc_bkops_stats_write, }; +#ifdef CONFIG_MMC_CMD_DEBUG +static int mmc_cmd_stats_show(struct seq_file *s, void *data) +{ + int i; + struct mmc_card *card = s->private; + unsigned long long t; + unsigned long rem_nsec; + + if (card->cmd_stats.wrapped) { + for (i = card->cmd_stats.next_idx; i < CMD_QUEUE_SIZE; i++) { + t = card->cmd_stats.cmdq[i].timestamp; + rem_nsec = do_div(t, 1000000000); + seq_printf(s, "[%5llu.%06lu] CMD%u arg %08x flags %08x\n", + t, (rem_nsec/1000), + card->cmd_stats.cmdq[i].opcode, + card->cmd_stats.cmdq[i].arg, + card->cmd_stats.cmdq[i].flags); + } + } + + for (i = 0; i < card->cmd_stats.next_idx; i++) { + t = card->cmd_stats.cmdq[i].timestamp; + rem_nsec = do_div(t, 1000000000); + seq_printf(s, "[%5llu.%06lu] CMD%u arg %08x flags %08x\n", + t, (rem_nsec/1000), + card->cmd_stats.cmdq[i].opcode, + card->cmd_stats.cmdq[i].arg, + card->cmd_stats.cmdq[i].flags); + } + + return 0; +} + +static int mmc_cmd_stats_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, mmc_cmd_stats_show, inode->i_private); +} + +static const struct file_operations mmc_dbg_card_rq_cmdq_fops = { + .open = mmc_cmd_stats_open, + .read = seq_read, +}; +#endif + void mmc_add_card_debugfs(struct mmc_card *card) { struct mmc_host *host = card->host; @@ -871,7 +920,12 @@ void mmc_add_card_debugfs(struct mmc_card *card) if (!debugfs_create_file("status", S_IRUSR, root, card, &mmc_dbg_card_status_fops)) goto err; - +#ifdef CONFIG_MMC_CMD_DEBUG + if (mmc_card_mmc(card) || mmc_card_sd(card)) + if (!debugfs_create_file("mmc_cmd_stats", S_IRUSR, root, + card, &mmc_dbg_card_rq_cmdq_fops)) + goto err; +#endif if (mmc_card_mmc(card)) if (!debugfs_create_file("ext_csd", S_IRUSR, root, card, &mmc_dbg_ext_csd_fops)) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6f4f81a370d8eb7319fd71cfd9b26ee57473eb36..7173bf56c2c5bddd206ef75530c6cfd1ae2648f9 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1323,6 +1323,10 @@ int mmc_hs400_to_hs200(struct mmc_card *card) if (host->caps & MMC_CAP_WAIT_WHILE_BUSY) send_status = false; + /* Reduce frequency to HS */ + max_dtr = card->ext_csd.hs_max_dtr; + mmc_set_clock(host, max_dtr); + /* Switch HS400 to HS DDR */ val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, @@ -1333,10 +1337,6 @@ int mmc_hs400_to_hs200(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_DDR52); - /* Reduce frequency to HS */ - max_dtr = card->ext_csd.hs_max_dtr; - mmc_set_clock(host, max_dtr); - if (!send_status) { err = mmc_switch_status(card, false); if (err) @@ -2056,11 +2056,11 @@ reinit: } card->clk_scaling_lowest = host->f_min; - if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) || - (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)) + if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS400) || + (card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS200)) card->clk_scaling_highest = card->ext_csd.hs200_max_dtr; - else if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) || - (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52)) + else if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS) || + (card->mmc_avail_type | EXT_CSD_CARD_TYPE_DDR_52)) card->clk_scaling_highest = card->ext_csd.hs_max_dtr; else card->clk_scaling_highest = card->csd.max_dtr; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 21836eac001eaa11f367a4406ad185bd412f55a8..2bcfe5d980c6d44eba37203f9268867d19383052 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -9,6 +9,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -312,7 +317,7 @@ static int mmc_read_switch(struct mmc_card *card) * The argument does not matter, as the support bits do not * change with the arguments. */ - err = mmc_sd_switch(card, 0, 0, 0, status); + err = mmc_sd_switch(card, 0, 0, 1, status); if (err) { /* * If the host or the card can't do the switch, @@ -1237,10 +1242,7 @@ static int mmc_sd_suspend(struct mmc_host *host) if (!err) { pm_runtime_disable(&host->card->dev); pm_runtime_set_suspended(&host->card->dev); - /* if suspend fails, force mmc_detect_change during resume */ - } else if (mmc_bus_manual_resume(host)) - host->ignore_bus_resume_flags = true; - + } MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; @@ -1289,7 +1291,6 @@ static int _mmc_sd_resume(struct mmc_host *host) if (err) { pr_err("%s: %s: mmc_sd_init_card_failed (%d)\n", mmc_hostname(host), __func__, err); - mmc_power_off(host); goto out; } mmc_card_clr_suspended(host->card); diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 27117ba4707312dad5f06bbf142ffe50c34efa22..1de6e53d9435ce31d9f5d29bc8cefe891083c935 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -7,6 +7,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -26,17 +31,89 @@ struct mmc_gpio { bool override_ro_active_level; bool override_cd_active_level; irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id); + bool status; + int uim2_gpio; char *ro_label; char cd_label[0]; +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME + bool suspended; +#endif }; +int mmc_gpio_get_status(struct mmc_host *host) +{ + int ret = -ENOSYS; + struct mmc_gpio *ctx = host->slot.handler_priv; + + if (!ctx || !gpio_is_valid(desc_to_gpio(ctx->cd_gpio))) + goto out; + + ret = !gpio_get_value_cansleep(desc_to_gpio(ctx->cd_gpio)) ^ + !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); +out: + return ret; +} + +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME +void mmc_cd_prepare_suspend(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + if (!ctx) + return; + + ctx->suspended = true; +} +EXPORT_SYMBOL(mmc_cd_prepare_suspend); +#endif + static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) { /* Schedule a card detection after a debounce timeout */ struct mmc_host *host = dev_id; - - host->trigger_card_event = true; - mmc_detect_change(host, msecs_to_jiffies(200)); + struct mmc_gpio *ctx = host->slot.handler_priv; + int status; +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME + unsigned long flags; +#endif + + if (!host->ops) + goto out; + + status = mmc_gpio_get_status(host); + if (unlikely(status < 0)) + goto out; + + if (status == 0) + mmc_gpio_set_uim2_en(host, 0); + + if (status ^ ctx->status) { + pr_info("%s: slot status change detected (%d -> %d), GPIO_ACTIVE_%s\n", + mmc_hostname(host), ctx->status, status, + (host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH) ? + "HIGH" : "LOW"); + ctx->status = status; + + host->trigger_card_event = true; +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME + if (ctx->suspended) { + /* + * host->rescan_disable is normally set to 0 in + * PM_POST_RESTORE of mmc_pm_notify but in case + * of a deferred resume we might get IRQ before + * it is called. + */ + spin_lock_irqsave(&host->lock, flags); + host->rescan_disable = 0; + spin_unlock_irqrestore(&host->lock, flags); + } + ctx->suspended = false; +#endif + + /* Schedule a card detection after a debounce timeout */ + mmc_detect_change(host, msecs_to_jiffies(200)); + } +out: return IRQ_HANDLED; } @@ -53,6 +130,7 @@ int mmc_gpio_alloc(struct mmc_host *host) snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); host->slot.handler_priv = ctx; host->slot.cd_irq = -EINVAL; + ctx->uim2_gpio = -EINVAL; } return ctx ? 0 : -ENOMEM; @@ -136,6 +214,12 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host) if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) irq = -EINVAL; + ret = mmc_gpio_get_status(host); + if (ret < 0) + pr_warn("%s: failed to init cd_gpio status\n", mmc_hostname(host)); + else + ctx->status = ret; + if (irq >= 0) { if (!ctx->cd_gpio_isr) ctx->cd_gpio_isr = mmc_gpio_cd_irqt; @@ -207,6 +291,9 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, ctx->override_cd_active_level = true; ctx->cd_gpio = gpio_to_desc(gpio); +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME + ctx->suspended = false; +#endif return 0; } EXPORT_SYMBOL(mmc_gpio_request_cd); @@ -303,3 +390,42 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, return 0; } EXPORT_SYMBOL(mmc_gpiod_request_ro); + + +void mmc_gpio_init_uim2(struct mmc_host *host, unsigned int gpio) +{ + struct mmc_gpio *ctx; + + ctx = host->slot.handler_priv; + + ctx->uim2_gpio = gpio; + + pr_info("## %s: %s: gpio=%d\n", mmc_hostname(host), __func__, gpio); + + mmc_gpio_set_uim2_en(host, 0); +} +EXPORT_SYMBOL(mmc_gpio_init_uim2); + +void mmc_gpio_set_uim2_en(struct mmc_host *host, int value) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + if (!ctx || !gpio_is_valid(ctx->uim2_gpio)) { + pr_err("## %s: gpio_set failure: ctx=%p, uim2_gpio=%d\n", + mmc_hostname(host), ctx, ctx ? ctx->uim2_gpio : 0); + return; + } + gpio_set_value(ctx->uim2_gpio, value); + pr_info("## %s: %s: gpio=%d value=%d\n", mmc_hostname(host), __func__, + ctx->uim2_gpio, value); +} +EXPORT_SYMBOL(mmc_gpio_set_uim2_en); + +void mmc_gpio_tray_close_set_uim2(struct mmc_host *host, int value) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + if (ctx && ctx->status) + mmc_gpio_set_uim2_en(host, value); +} +EXPORT_SYMBOL(mmc_gpio_tray_close_set_uim2); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index acece3299756e997b15020a100ad14def283c020..ab8452c73dba04974cd992c6f1eee9372cf37996 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -8,6 +8,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 76764bbb0c67bc57f712171eafe9a9d38432b319..458b93b71c0e26fed835d6a6582aa92d3db3097b 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -14,6 +14,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -142,7 +147,6 @@ #define CORE_START_CDC_TRAFFIC (1 << 6) #define CORE_PWRSAVE_DLL (1 << 3) -#define CORE_FIFO_ALT_EN (1 << 10) #define CORE_CMDEN_HS400_INPUT_MASK_CNT (1 << 13) #define CORE_DDR_CAL_EN (1 << 0) @@ -1140,7 +1144,6 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) bool drv_type_changed = false; struct mmc_card *card = host->mmc->card; int sts_retry; - u8 last_good_phase = 0; /* * Tuning is required for SDR104, HS200 and HS400 cards and @@ -1226,22 +1229,6 @@ retry: mmc_wait_for_req(mmc, &mrq); if (card && (cmd.error || data.error)) { - /* - * Set the dll to last known good phase while sending - * status command to ensure that status command won't - * fail due to bad phase. - */ - if (tuned_phase_cnt) - last_good_phase = - tuned_phases[tuned_phase_cnt-1]; - else if (msm_host->saved_tuning_phase != - INVALID_TUNING_PHASE) - last_good_phase = msm_host->saved_tuning_phase; - - rc = msm_config_cm_dll_phase(host, last_good_phase); - if (rc) - goto kfree; - sts_cmd.opcode = MMC_SEND_STATUS; sts_cmd.arg = card->rca << 16; sts_cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; @@ -1844,6 +1831,12 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, if (gpio_is_valid(pdata->status_gpio) && !(flags & OF_GPIO_ACTIVE_LOW)) pdata->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; + pdata->uim2_gpio = of_get_named_gpio(np, "uim2-gpios", 0); + if (!gpio_is_valid(pdata->uim2_gpio)) { + pr_err("## %s: gpio_is_valid(pdata->uim2_gpio)=%d: failure\n", + mmc_hostname(msm_host->mmc), pdata->uim2_gpio); + } + of_property_read_u32(np, "qcom,bus-width", &bus_width); if (bus_width == 8) pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA; @@ -4155,7 +4148,7 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, * starts coming. */ if ((major == 1) && ((minor == 0x42) || (minor == 0x46) || - (minor == 0x49) || (minor >= 0x6b))) + (minor == 0x49))) msm_host->use_14lpp_dll = true; /* Fake 3.0V support for SDIO devices which requires such voltage */ @@ -4180,10 +4173,8 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, /* keep track of the value in SDHCI_CAPABILITIES */ msm_host->caps_0 = caps; - if ((major == 1) && (minor >= 0x6b)) { + if ((major == 1) && (minor >= 0x6b)) msm_host->ice_hci_support = true; - host->cdr_support = true; - } } #ifdef CONFIG_MMC_CQ_HCI @@ -4479,14 +4470,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) writel_relaxed(CORE_VENDOR_SPEC_POR_VAL, host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC); - /* - * Ensure SDHCI FIFO is enabled by disabling alternative FIFO - */ - writel_relaxed((readl_relaxed(host->ioaddr + - msm_host_offset->CORE_VENDOR_SPEC3) & - ~CORE_FIFO_ALT_EN), host->ioaddr + - msm_host_offset->CORE_VENDOR_SPEC3); - if (!msm_host->mci_removed) { /* Set HC_MODE_EN bit in HC_MODE register */ writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE)); @@ -4658,6 +4641,13 @@ static int sdhci_msm_probe(struct platform_device *pdev) } } + if (gpio_is_valid(msm_host->pdata->uim2_gpio)) { + mmc_gpio_init_uim2(msm_host->mmc, msm_host->pdata->uim2_gpio); + } else { + pr_err("## %s: can't set uim2_gpio: %d\n", mmc_hostname(host->mmc), + msm_host->pdata->uim2_gpio); + } + if ((sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) && (dma_supported(mmc_dev(host->mmc), DMA_BIT_MASK(64)))) { host->dma_mask = DMA_BIT_MASK(64); @@ -4741,9 +4731,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) mmc_hostname(host->mmc), __func__, ret); device_remove_file(&pdev->dev, &msm_host->auto_cmd21_attr); } - if (sdhci_msm_is_bootdevice(&pdev->dev)) - mmc_flush_detect_work(host->mmc); - /* Successful initialization */ goto out; @@ -5021,7 +5008,7 @@ static int sdhci_msm_suspend_noirq(struct device *dev) } static const struct dev_pm_ops sdhci_msm_pmops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume) + SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume) SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume, NULL) .suspend_noirq = sdhci_msm_suspend_noirq, diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h index 79949c2c537f8f79e4d0124d498f96328fa0234e..841b2462a197c060e25ff0d2e34262c2f6f000a2 100644 --- a/drivers/mmc/host/sdhci-msm.h +++ b/drivers/mmc/host/sdhci-msm.h @@ -11,6 +11,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __SDHCI_MSM_H__ #define __SDHCI_MSM_H__ @@ -143,6 +148,7 @@ struct sdhci_msm_pltfm_data { struct sdhci_msm_pin_data *pin_data; struct sdhci_pinctrl_data *pctrl_data; int status_gpio; /* card detection GPIO that is configured as IRQ */ + int uim2_gpio; struct sdhci_msm_bus_voting_data *voting_data; u32 *sup_clk_table; unsigned char sup_clk_cnt; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5906bba0aeffcf86df6854553760cc5017f1b1d5..a5ff9f73dfbcb204a33b73f121ed263463a9c29a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3041,6 +3041,11 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) * above in sdhci_cmd_irq(). */ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) { + if (intmask & SDHCI_INT_DATA_TIMEOUT) { + host->cmd->error = -ETIMEDOUT; + tasklet_schedule(&host->finish_tasklet); + return; + } if (intmask & SDHCI_INT_DATA_END) { /* * Some cards handle busy-end interrupt @@ -3054,20 +3059,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) return; } if (host->quirks2 & - SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD) { - pr_err_ratelimited("%s: %s: ignoring interrupt: 0x%08x due to DATATOUT_FOR_R1B quirk\n", - mmc_hostname(host->mmc), - __func__, intmask); - MMC_TRACE(host->mmc, - "%s: Quirk ignoring intr: 0x%08x\n", - __func__, intmask); + SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD) return; - } - if (intmask & SDHCI_INT_DATA_TIMEOUT) { - host->cmd->error = -ETIMEDOUT; - tasklet_schedule(&host->finish_tasklet); - return; - } } pr_err("%s: Got data interrupt 0x%08x even " @@ -3640,7 +3633,7 @@ static void sdhci_cmdq_set_transfer_params(struct mmc_host *mmc) ctrl |= SDHCI_CTRL_ADMA32; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } - if (host->ops->toggle_cdr && !host->cdr_support) + if (host->ops->toggle_cdr) host->ops->toggle_cdr(host, false); } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 81aecb90ac8d98e2730e1d32e282848821ade58b..93129b26dc5ecb008e279bf500593d85be509c7a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -516,7 +516,7 @@ struct sdhci_host { * Some controllers may use PIO mode to workaround HW issues in ADMA for * eMMC tuning commands. */ -#define SDHCI_QUIRK2_USE_PIO_FOR_EMMC_TUNING (1 << 29) +#define SDHCI_QUIRK2_USE_PIO_FOR_EMMC_TUNING (1 << 23) int irq; /* Device IRQ */ @@ -564,7 +564,6 @@ struct sdhci_host { bool runtime_suspended; /* Host is runtime suspended */ bool bus_on; /* Bus power prevents runtime suspend */ bool preset_enabled; /* Preset is enabled */ - bool cdr_support; struct mmc_request *mrq; /* Current request */ struct mmc_command *cmd; /* Current command */ diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 9190057535e6d860a507a804cad4cc3b2632099b..5abab88008910de2701eb56442e4af4d69668460 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -66,13 +66,11 @@ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master, { uint32_t buf; size_t bytes_read; - int err; - err = mtd_read(master, offset, sizeof(buf), &bytes_read, - (uint8_t *)&buf); - if (err && !mtd_is_bitflip(err)) { - pr_err("mtd_read error while parsing (offset: 0x%X): %d\n", - offset, err); + if (mtd_read(master, offset, sizeof(buf), &bytes_read, + (uint8_t *)&buf) < 0) { + pr_err("mtd_read error while parsing (offset: 0x%X)!\n", + offset); goto out_default; } @@ -97,7 +95,6 @@ static int bcm47xxpart_parse(struct mtd_info *master, int trx_part = -1; int last_trx_part = -1; int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, }; - int err; /* * Some really old flashes (like AT45DB*) had smaller erasesize-s, but @@ -121,8 +118,8 @@ static int bcm47xxpart_parse(struct mtd_info *master, /* Parse block by block looking for magics */ for (offset = 0; offset <= master->size - blocksize; offset += blocksize) { - /* Nothing more in higher memory on BCM47XX (MIPS) */ - if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000) + /* Nothing more in higher memory */ + if (offset >= 0x2000000) break; if (curr_part >= BCM47XXPART_MAX_PARTS) { @@ -131,11 +128,10 @@ static int bcm47xxpart_parse(struct mtd_info *master, } /* Read beginning of the block */ - err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ, - &bytes_read, (uint8_t *)buf); - if (err && !mtd_is_bitflip(err)) { - pr_err("mtd_read error while parsing (offset: 0x%X): %d\n", - offset, err); + if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ, + &bytes_read, (uint8_t *)buf) < 0) { + pr_err("mtd_read error while parsing (offset: 0x%X)!\n", + offset); continue; } @@ -256,11 +252,10 @@ static int bcm47xxpart_parse(struct mtd_info *master, } /* Read middle of the block */ - err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read, - (uint8_t *)buf); - if (err && !mtd_is_bitflip(err)) { - pr_err("mtd_read error while parsing (offset: 0x%X): %d\n", - offset, err); + if (mtd_read(master, offset + 0x8000, 0x4, + &bytes_read, (uint8_t *)buf) < 0) { + pr_err("mtd_read error while parsing (offset: 0x%X)!\n", + offset); continue; } @@ -280,11 +275,10 @@ static int bcm47xxpart_parse(struct mtd_info *master, } offset = master->size - possible_nvram_sizes[i]; - err = mtd_read(master, offset, 0x4, &bytes_read, - (uint8_t *)buf); - if (err && !mtd_is_bitflip(err)) { - pr_err("mtd_read error while reading (offset 0x%X): %d\n", - offset, err); + if (mtd_read(master, offset, 0x4, &bytes_read, + (uint8_t *)buf) < 0) { + pr_err("mtd_read error while reading at offset 0x%X!\n", + offset); continue; } diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 64d6f053c2a5f9ff8d37e0924801707cef718603..37e4135ab213d64b158f7165994e5000d1dd4bb7 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1057,13 +1057,6 @@ static int spansion_quad_enable(struct spi_nor *nor) return -EINVAL; } - ret = spi_nor_wait_till_ready(nor); - if (ret) { - dev_err(nor->dev, - "timeout while writing configuration register\n"); - return ret; - } - /* read back and check it */ ret = read_cr(nor); if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { diff --git a/drivers/net/can/spi/rh850.c b/drivers/net/can/spi/rh850.c index d2b6e8caa112579f1d2281a348c5f7718a2d6cb5..a93f979da9ede4cb25b4be375a9d0c6e28bcadcd 100644 --- a/drivers/net/can/spi/rh850.c +++ b/drivers/net/can/spi/rh850.c @@ -1020,8 +1020,6 @@ static int rh850_create_netdev(struct spi_device *spi, return -ENOMEM; } - netdev->mtu = CANFD_MTU; - netdev_priv_data = netdev_priv(netdev); netdev_priv_data->rh850_can = priv_data; netdev_priv_data->netdev_index = index; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 75e6e7e6baed843d30e110e979e1cb90bc7c3a60..5e6238e0b2bd4a1f396e366f6638ad79490c249b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -2732,10 +2732,8 @@ static int xgbe_init(struct xgbe_prv_data *pdata) /* Flush Tx queues */ ret = xgbe_flush_tx_queues(pdata); - if (ret) { - netdev_err(pdata->netdev, "error flushing TX queues\n"); + if (ret) return ret; - } /* * Initialize DMA related features diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 64034ff081a0c8e057e0f488b4ddffe453eb480d..865b7e0b133b33d1d2e50a685c0adbdde5ea8e13 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -877,9 +877,7 @@ static int xgbe_start(struct xgbe_prv_data *pdata) DBGPR("-->xgbe_start\n"); - ret = hw_if->init(pdata); - if (ret) - return ret; + hw_if->init(pdata); ret = phy_if->phy_start(pdata); if (ret) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index a5e4b4b93d1bdc7da00d6f594d5172132e456c24..b56c9c581359ef56618ff9554f1d1902be7d5ce9 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -255,16 +255,15 @@ static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring) while (ring->start != ring->end) { int slot_idx = ring->start % BGMAC_TX_RING_SLOTS; struct bgmac_slot_info *slot = &ring->slots[slot_idx]; - u32 ctl0, ctl1; + u32 ctl1; int len; if (slot_idx == empty_slot) break; - ctl0 = le32_to_cpu(ring->cpu_base[slot_idx].ctl0); ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1); len = ctl1 & BGMAC_DESC_CTL1_LEN; - if (ctl0 & BGMAC_DESC_CTL0_SOF) + if (ctl1 & BGMAC_DESC_CTL0_SOF) /* Unmap no longer used buffer */ dma_unmap_single(dma_dev, slot->dma_addr, len, DMA_TO_DEVICE); @@ -470,11 +469,6 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, len -= ETH_FCS_LEN; skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE); - if (unlikely(!skb)) { - bgmac_err(bgmac, "build_skb failed\n"); - put_page(virt_to_head_page(buf)); - break; - } skb_put(skb, BGMAC_RX_FRAME_OFFSET + BGMAC_RX_BUF_OFFSET + len); skb_pull(skb, BGMAC_RX_FRAME_OFFSET + @@ -1308,8 +1302,7 @@ static int bgmac_open(struct net_device *net_dev) phy_start(bgmac->phy_dev); - netif_start_queue(net_dev); - + netif_carrier_on(net_dev); return 0; } @@ -1583,11 +1576,6 @@ static int bgmac_probe(struct bcma_device *core) dev_warn(&core->dev, "Using random MAC: %pM\n", mac); } - /* This (reset &) enable is not preset in specs or reference driver but - * Broadcom does it in arch PCI code when enabling fake PCI device. - */ - bcma_core_enable(core, 0); - /* Allocation and references */ net_dev = alloc_etherdev(sizeof(*bgmac)); if (!net_dev) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 7b8638ddb6731c2400b648580f85f3ea9ba770fe..1795c935ff023fcf795008a49a9a4cd0fce63d9c 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1052,7 +1052,7 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, err: spin_unlock_bh(&adapter->mcc_lock); - if (base_status(status) == MCC_STATUS_UNAUTHORIZED_REQUEST) + if (status == MCC_STATUS_UNAUTHORIZED_REQUEST) status = -EPERM; return status; diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 4cd2a7d0124faefd592929fbef31e1d6630eb6ae..6a061f17a44fbf0c2f1e56b4202729b10810385e 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2939,7 +2939,7 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, size, GFAR_RXB_TRUESIZE); /* try reuse page */ - if (unlikely(page_count(page) != 1 || page_is_pfmemalloc(page))) + if (unlikely(page_count(page) != 1)) return false; /* change offset to the other half */ diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 2f9b12cf9ee5b780a13acdad16f143a630e2f413..f9e4988ea30eb1899f360b9a04de040594e50aec 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1602,11 +1602,8 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) netdev->netdev_ops = &ibmveth_netdev_ops; netdev->ethtool_ops = &netdev_ethtool_ops; SET_NETDEV_DEV(netdev, &dev->dev); - netdev->hw_features = NETIF_F_SG; - if (vio_get_attribute(dev, "ibm,illan-options", NULL) != NULL) { - netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM; - } + netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; netdev->features |= netdev->hw_features; diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c index 07eabf72c480c2198fe0db96cecaa852e1e9b3e9..d74f5f4e57824a97a3b745d4cbaa77098ad69ba3 100644 --- a/drivers/net/ethernet/korina.c +++ b/drivers/net/ethernet/korina.c @@ -900,10 +900,10 @@ static void korina_restart_task(struct work_struct *work) DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR, &lp->rx_dma_regs->dmasm); - napi_disable(&lp->napi); - korina_free_ring(dev); + napi_disable(&lp->napi); + if (korina_init(dev) < 0) { printk(KERN_ERR "%s: cannot restart device\n", dev->name); return; @@ -1064,12 +1064,12 @@ static int korina_close(struct net_device *dev) tmp = tmp | DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR; writel(tmp, &lp->rx_dma_regs->dmasm); + korina_free_ring(dev); + napi_disable(&lp->napi); cancel_work_sync(&lp->restart_task); - korina_free_ring(dev); - free_irq(lp->rx_irq, dev); free_irq(lp->tx_irq, dev); free_irq(lp->ovr_irq, dev); diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 15056f06754a91407b0f00b01cae7a4c9f1772b2..71ec9cb08e067a7d03e874d7c1d2f6ae32ed646d 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2446,7 +2446,7 @@ static void mvneta_start_dev(struct mvneta_port *pp) mvneta_port_enable(pp); /* Enable polling on the port */ - for_each_online_cpu(cpu) { + for_each_present_cpu(cpu) { struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu); napi_enable(&port->napi); @@ -2472,7 +2472,7 @@ static void mvneta_stop_dev(struct mvneta_port *pp) phy_stop(pp->phy_dev); - for_each_online_cpu(cpu) { + for_each_present_cpu(cpu) { struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu); napi_disable(&port->napi); @@ -2902,11 +2902,13 @@ err_cleanup_rxqs: static int mvneta_stop(struct net_device *dev) { struct mvneta_port *pp = netdev_priv(dev); + int cpu; mvneta_stop_dev(pp); mvneta_mdio_remove(pp); unregister_cpu_notifier(&pp->cpu_notifier); - on_each_cpu(mvneta_percpu_disable, pp, true); + for_each_present_cpu(cpu) + smp_call_function_single(cpu, mvneta_percpu_disable, pp, true); free_percpu_irq(dev->irq, pp->ports); mvneta_cleanup_rxqs(pp); mvneta_cleanup_txqs(pp); diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index ff77b8b608bd0eca364196732fe8d252e39152bf..603d1c3d3b2ea1a8a98de110f1e777f1d751e649 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -542,9 +542,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) break; case MLX4_EVENT_TYPE_SRQ_LIMIT: - mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT. srq_no=0x%x, eq 0x%x\n", - __func__, be32_to_cpu(eqe->event.srq.srqn), - eq->eqn); + mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT\n", + __func__); case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: if (mlx4_is_master(dev)) { /* forward only to slave owning the SRQ */ @@ -559,19 +558,15 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) eq->eqn, eq->cons_index, ret); break; } - if (eqe->type == - MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) - mlx4_warn(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n", - __func__, slave, - be32_to_cpu(eqe->event.srq.srqn), - eqe->type, eqe->subtype); + mlx4_warn(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n", + __func__, slave, + be32_to_cpu(eqe->event.srq.srqn), + eqe->type, eqe->subtype); if (!ret && slave != dev->caps.function) { - if (eqe->type == - MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) - mlx4_warn(dev, "%s: sending event %02x(%02x) to slave:%d\n", - __func__, eqe->type, - eqe->subtype, slave); + mlx4_warn(dev, "%s: sending event %02x(%02x) to slave:%d\n", + __func__, eqe->type, + eqe->subtype, slave); mlx4_slave_event(dev, slave, eqe); break; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index f5c1f4acc57b7d3617bd45c052f00aa2bb30cc13..1e611980cf99025bf152d56b1e5afb53032f40e1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -153,9 +153,8 @@ static struct mlx5_profile profile[] = { }, }; -#define FW_INIT_TIMEOUT_MILI 2000 -#define FW_INIT_WAIT_MS 2 -#define FW_PRE_INIT_TIMEOUT_MILI 10000 +#define FW_INIT_TIMEOUT_MILI 2000 +#define FW_INIT_WAIT_MS 2 static int wait_fw_init(struct mlx5_core_dev *dev, u32 max_wait_mili) { @@ -935,15 +934,6 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv) */ dev->state = MLX5_DEVICE_STATE_UP; - /* wait for firmware to accept initialization segments configurations - */ - err = wait_fw_init(dev, FW_PRE_INIT_TIMEOUT_MILI); - if (err) { - dev_err(&dev->pdev->dev, "Firmware over %d MS in pre-initializing state, aborting\n", - FW_PRE_INIT_TIMEOUT_MILI); - goto out; - } - err = mlx5_cmd_init(dev); if (err) { dev_err(&pdev->dev, "Failed initializing command interface, aborting\n"); diff --git a/drivers/net/ethernet/msm/msm_rmnet_mhi.c b/drivers/net/ethernet/msm/msm_rmnet_mhi.c index de14dcc6f4ed678614cfc4a77d41be1fc6939e98..60b7a64c2edbc07ec6b4f27b395557ada6efabe2 100644 --- a/drivers/net/ethernet/msm/msm_rmnet_mhi.c +++ b/drivers/net/ethernet/msm/msm_rmnet_mhi.c @@ -942,13 +942,10 @@ net_dev_reg_fail: netif_napi_del(&(rmnet_mhi_ptr->napi)); free_netdev(rmnet_mhi_ptr->dev); net_dev_alloc_fail: - if (rmnet_mhi_ptr->rx_client_handle) { - mhi_close_channel(rmnet_mhi_ptr->rx_client_handle); - rmnet_mhi_ptr->dev = NULL; - } + mhi_close_channel(rmnet_mhi_ptr->rx_client_handle); + rmnet_mhi_ptr->dev = NULL; mhi_rx_chan_start_fail: - if (rmnet_mhi_ptr->tx_client_handle) - mhi_close_channel(rmnet_mhi_ptr->tx_client_handle); + mhi_close_channel(rmnet_mhi_ptr->tx_client_handle); mhi_tx_chan_start_fail: rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited ret %d.\n", ret); return ret; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 585e90f8341d4ff7f9ef64bf30ea4dab9f0e1e0d..1e61d4da72dbf7ec7e42a7491f38565b0117fff8 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -221,6 +221,18 @@ static void ravb_ring_free(struct net_device *ndev, int q) int ring_size; int i; + /* Free RX skb ringbuffer */ + if (priv->rx_skb[q]) { + for (i = 0; i < priv->num_rx_ring[q]; i++) + dev_kfree_skb(priv->rx_skb[q][i]); + } + kfree(priv->rx_skb[q]); + priv->rx_skb[q] = NULL; + + /* Free aligned TX buffers */ + kfree(priv->tx_align[q]); + priv->tx_align[q] = NULL; + if (priv->rx_ring[q]) { for (i = 0; i < priv->num_rx_ring[q]; i++) { struct ravb_ex_rx_desc *desc = &priv->rx_ring[q][i]; @@ -249,18 +261,6 @@ static void ravb_ring_free(struct net_device *ndev, int q) priv->tx_ring[q] = NULL; } - /* Free RX skb ringbuffer */ - if (priv->rx_skb[q]) { - for (i = 0; i < priv->num_rx_ring[q]; i++) - dev_kfree_skb(priv->rx_skb[q][i]); - } - kfree(priv->rx_skb[q]); - priv->rx_skb[q] = NULL; - - /* Free aligned TX buffers */ - kfree(priv->tx_align[q]); - priv->tx_align[q] = NULL; - /* Free TX skb ringbuffer. * SKBs are freed by ravb_tx_free() call above. */ diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 8e832ba8ab24b6e707e2f68a32c3b8f5e60b8fdb..d790cb8d9db3cc62d70c99c8ce877242ea3ed16b 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -2796,11 +2796,6 @@ const struct efx_nic_type falcon_a1_nic_type = { .timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH, .offload_features = NETIF_F_IP_CSUM, .mcdi_max_ver = -1, -#ifdef CONFIG_SFC_SRIOV - .vswitching_probe = efx_port_dummy_op_int, - .vswitching_restore = efx_port_dummy_op_int, - .vswitching_remove = efx_port_dummy_op_void, -#endif }; const struct efx_nic_type falcon_b0_nic_type = { @@ -2902,9 +2897,4 @@ const struct efx_nic_type falcon_b0_nic_type = { .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE, .mcdi_max_ver = -1, .max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS, -#ifdef CONFIG_SFC_SRIOV - .vswitching_probe = efx_port_dummy_op_int, - .vswitching_restore = efx_port_dummy_op_int, - .vswitching_remove = efx_port_dummy_op_void, -#endif }; diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index e83acc608678525405ad80acec5691495216caae..84b9cca152ebbc18d60dde1aa19dd49debeb8c1c 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -907,7 +907,7 @@ static void decode_txts(struct dp83640_private *dp83640, if (overflow) { pr_debug("tx timestamp queue overflow, count %d\n", overflow); while (skb) { - kfree_skb(skb); + skb_complete_tx_timestamp(skb, NULL); skb = skb_dequeue(&dp83640->tx_queue); } return; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index ebec2dceff4525e4c62969090daa7498186d0881..d2701c53ed681b55138de764d53bafa9bb911509 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -822,6 +822,8 @@ static int marvell_read_status(struct phy_device *phydev) phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) | mii_lpa_to_ethtool_lpa_t(lpa); + lpa &= adv; + if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) phydev->duplex = DUPLEX_FULL; else diff --git a/drivers/net/phy/mdio-bcm-iproc.c b/drivers/net/phy/mdio-bcm-iproc.c index 46fe1ae919a30a9a9b7644b5862f4a5bfa0b56ef..c0b4e65267af8b541974bd3a246897e1c38a9ac9 100644 --- a/drivers/net/phy/mdio-bcm-iproc.c +++ b/drivers/net/phy/mdio-bcm-iproc.c @@ -81,6 +81,8 @@ static int iproc_mdio_read(struct mii_bus *bus, int phy_id, int reg) if (rc) return rc; + iproc_mdio_config_clk(priv->base); + /* Prepare the read operation */ cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) | (reg << MII_DATA_RA_SHIFT) | @@ -110,6 +112,8 @@ static int iproc_mdio_write(struct mii_bus *bus, int phy_id, if (rc) return rc; + iproc_mdio_config_clk(priv->base); + /* Prepare the write operation */ cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) | (reg << MII_DATA_RA_SHIFT) | @@ -159,8 +163,6 @@ static int iproc_mdio_probe(struct platform_device *pdev) bus->read = iproc_mdio_read; bus->write = iproc_mdio_write; - iproc_mdio_config_clk(priv->base); - rc = of_mdiobus_register(bus, pdev->dev.of_node); if (rc) { dev_err(&pdev->dev, "MDIO bus registration failed\n"); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index c8b85f1069ffab4fa42637b6bd8300fab495cd6d..e13ad6cdcc2216ca1d43b78bb41cac12933fe2b4 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -539,8 +539,6 @@ static int ksz9031_read_status(struct phy_device *phydev) if ((regval & 0xFF) == 0xFF) { phy_init_hw(phydev); phydev->link = 0; - if (phydev->drv->config_intr && phy_interrupt_is_valid(phydev)) - phydev->drv->config_intr(phydev); } return 0; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index e5bb870b5461aa9afd81b1a41f36bbf6f4a58234..a8432fc043ac1f887e7e25b09bdfa35a8333ae91 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -21,6 +21,11 @@ * * ==FILEVERSION 20041108== */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 8dfc75250583a5a6baad7fac7c62b4ca2a89eec7..7f7c87762bc69f19a1c13fbe7f8babc583e710f2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -47,16 +47,8 @@ module_param(gso, bool, 0444); */ DECLARE_EWMA(pkt_len, 1, 64) -/* With mergeable buffers we align buffer address and use the low bits to - * encode its true size. Buffer size is up to 1 page so we need to align to - * square root of page size to ensure we reserve enough bits to encode the true - * size. - */ -#define MERGEABLE_BUFFER_MIN_ALIGN_SHIFT ((PAGE_SHIFT + 1) / 2) - /* Minimum alignment for mergeable packet buffers. */ -#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, \ - 1 << MERGEABLE_BUFFER_MIN_ALIGN_SHIFT) +#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256) #define VIRTNET_DRIVER_VERSION "1.0.0" diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index ac945f8781ace533713a4aa4bee1b2d294050956..349aecbc210a55b4a767f73fd4c83b714d186b02 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -733,15 +733,15 @@ static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) static void vrf_dev_uninit(struct net_device *dev) { struct net_vrf *vrf = netdev_priv(dev); -// struct slave_queue *queue = &vrf->queue; -// struct list_head *head = &queue->all_slaves; -// struct slave *slave, *next; + struct slave_queue *queue = &vrf->queue; + struct list_head *head = &queue->all_slaves; + struct slave *slave, *next; vrf_rtable_destroy(vrf); vrf_rt6_destroy(vrf); -// list_for_each_entry_safe(slave, next, head, list) -// vrf_del_slave(dev, slave->dev); + list_for_each_entry_safe(slave, next, head, list) + vrf_del_slave(dev, slave->dev); free_percpu(dev->dstats); dev->dstats = NULL; @@ -914,14 +914,6 @@ static int vrf_validate(struct nlattr *tb[], struct nlattr *data[]) static void vrf_dellink(struct net_device *dev, struct list_head *head) { - struct net_vrf *vrf = netdev_priv(dev); - struct slave_queue *queue = &vrf->queue; - struct list_head *all_slaves = &queue->all_slaves; - struct slave *slave, *next; - - list_for_each_entry_safe(slave, next, all_slaves, list) - vrf_del_slave(dev, slave->dev); - unregister_netdevice_queue(dev, head); } diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index dab3bf6649e61b85313de5ceeda62113932e7fb5..9a986ccd42e5cc0f97ed93b36a313670620a993c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2240,7 +2240,7 @@ static void vxlan_cleanup(unsigned long arg) = container_of(p, struct vxlan_fdb, hlist); unsigned long timeout; - if (f->state & (NUD_PERMANENT | NUD_NOARP)) + if (f->state & NUD_PERMANENT) continue; timeout = f->used + vxlan->cfg.age_interval * HZ; diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7945b1cd6244a9825368f0832aa1d2c5c4950348..2217e0cae4dada63da76172446d4e438e521076b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -311,14 +311,6 @@ config CNSS_CRYPTO from cnss platform driver. This crypto APIs used to generate cipher key and add support for the WLAN driver module security protocol. -config CNSS_QCA6290 - bool "Enable CNSS QCA6290 chipset specific changes" - ---help--- - This enables the changes from WLAN host driver that are specific to - CNSS QCA6290 chipset. - These changes are needed to support the new hardware architecture - for CNSS QCA6290 chipset. - source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/b43legacy/Kconfig" @@ -340,7 +332,6 @@ source "drivers/net/wireless/mwifiex/Kconfig" source "drivers/net/wireless/cw1200/Kconfig" source "drivers/net/wireless/rsi/Kconfig" source "drivers/net/wireless/cnss/Kconfig" -source "drivers/net/wireless/cnss2/Kconfig" source "drivers/net/wireless/cnss_genl/Kconfig" source "drivers/net/wireless/cnss_utils/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index f23a2fbc3afa25ff9640c9185ab4864af83e739f..704a976bdfb5fcd9f2a8f8c17057894f6f234daa 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -64,7 +64,6 @@ obj-$(CONFIG_RSI_91X) += rsi/ obj-$(CONFIG_WCNSS_CORE) += wcnss/ obj-$(CONFIG_CNSS) += cnss/ -obj-$(CONFIG_CNSS2) += cnss2/ obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/ obj-$(CONFIG_CNSS_CRYPTO) += cnss_crypto/ obj-$(CONFIG_CNSS_GENL) += cnss_genl/ diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 769f89e8d14c3e8335c569504563e37c37f75737..9cda1303c9e1bebe79117d4cf68364302b8f1d33 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1009,17 +1009,11 @@ void ath10k_ce_enable_interrupts(struct ath10k *ar) struct bus_opaque *ar_opaque = ath10k_bus_priv(ar); int ce_id; struct ath10k_ce_pipe *ce_state; - u8 ce_count; - if (QCA_REV_WCN3990(ar)) - ce_count = CE_COUNT; - else /* Skip the last copy engine, CE7 the diagnostic window, as that * uses polling and isn't initialized for interrupts. */ - ce_count = CE_COUNT - 1; - - for (ce_id = 0; ce_id < ce_count; ce_id++) { + for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) { ce_state = &ar_opaque->ce_states[ce_id]; ath10k_ce_per_engine_handler_adjust(ce_state); } diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 041d1d5eb7188bbf554370938dff6cbff12dc8ca..6906bddb229fc1f134ed2110bbfcda957cc27f98 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1886,12 +1886,6 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err_wmi_detach; } - /* If firmware indicates Full Rx Reorder support it must be used in a - * slightly different manner. Let HTT code know. - */ - ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, - ar->wmi.svc_map)); - status = ath10k_htt_rx_alloc(&ar->htt); if (status) { ath10k_err(ar, "failed to alloc htt rx: %d\n", status); @@ -1924,12 +1918,6 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err_hif_stop; } - status = ath10k_pktlog_connect(ar); - if (status) { - ath10k_err(ar, "could not connect pktlog: %d\n", status); - goto err_hif_stop; - } - status = ath10k_htc_start(&ar->htc); if (status) { ath10k_err(ar, "failed to start htc: %d\n", status); @@ -2009,6 +1997,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, } } + /* If firmware indicates Full Rx Reorder support it must be used in a + * slightly different manner. Let HTT code know. + */ + ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, + ar->wmi.svc_map)); + status = ath10k_htt_rx_ring_refill(ar); if (status) { ath10k_err(ar, "failed to refill htt rx ring: %d\n", status); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ffcf30756b9e1cc2955380a04ee09bf825241495..8ddbae96794d312d6c908e844e449a00cdd0d6e5 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -467,7 +467,6 @@ struct ath10k_debug { u64 fw_dbglog_mask; u32 fw_dbglog_level; u32 pktlog_filter; - enum ath10k_htc_ep_id eid; u32 reg_addr; u32 nf_cal_period; void *cal_data; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 42aab9b86af397b8ba15a24c9a501f13918fcf01..ec8063e7986a3e1adf626c468fb6a0f7be7f4c26 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -25,7 +25,6 @@ #include "core.h" #include "debug.h" #include "hif.h" -#include "htt.h" #include "wmi-ops.h" /* ms */ @@ -2618,178 +2617,6 @@ static const struct file_operations fops_fw_checksums = { .llseek = default_llseek, }; -static struct txctl_frm_hdr frm_hdr; - -static void ath10k_extract_frame_header(u8 *addr1, u8 *addr2, u8 *addr3) -{ - frm_hdr.bssid_tail = (addr1[IEEE80211_ADDR_LEN - 2] << BITS_PER_BYTE) - | (addr1[IEEE80211_ADDR_LEN - 1]); - frm_hdr.sa_tail = (addr2[IEEE80211_ADDR_LEN - 2] << BITS_PER_BYTE) - | (addr2[IEEE80211_ADDR_LEN - 1]); - frm_hdr.da_tail = (addr3[IEEE80211_ADDR_LEN - 2] << BITS_PER_BYTE) - | (addr3[IEEE80211_ADDR_LEN - 1]); -} - -static void ath10k_process_ieee_hdr(void *data) -{ - u8 dir; - struct ieee80211_frame *wh; - - if (!data) - return; - - wh = (struct ieee80211_frame *)(data); - frm_hdr.framectrl = *(u_int16_t *)(wh->i_fc); - frm_hdr.seqctrl = *(u_int16_t *)(wh->i_seq); - dir = (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK); - - if (dir == IEEE80211_FC1_DIR_TODS) - ath10k_extract_frame_header(wh->i_addr1, wh->i_addr2, - wh->i_addr3); - else if (dir == IEEE80211_FC1_DIR_FROMDS) - ath10k_extract_frame_header(wh->i_addr2, wh->i_addr3, - wh->i_addr1); - else - ath10k_extract_frame_header(wh->i_addr3, wh->i_addr2, - wh->i_addr1); -} - -static void ath10k_pktlog_process_rx(struct ath10k *ar, struct sk_buff *skb) -{ - struct ath10k_pktlog_hdr *hdr = (void *)skb->data; - struct ath_pktlog_txctl pktlog_tx_ctrl; - - switch (hdr->log_type) { - case ATH10K_PKTLOG_TYPE_TX_CTRL: { - spin_lock_bh(&ar->htt.tx_lock); - - memcpy((void *)(&pktlog_tx_ctrl.hdr), (void *)hdr, - sizeof(pktlog_tx_ctrl.hdr)); - pktlog_tx_ctrl.frm_hdr = frm_hdr; - memcpy((void *)pktlog_tx_ctrl.txdesc_ctl, (void *)hdr->payload, - __le16_to_cpu(hdr->size)); - pktlog_tx_ctrl.hdr.size = sizeof(pktlog_tx_ctrl) - - sizeof(pktlog_tx_ctrl.hdr); - - spin_unlock_bh(&ar->htt.tx_lock); - - trace_ath10k_htt_pktlog(ar, (void *)&pktlog_tx_ctrl, - sizeof(pktlog_tx_ctrl)); - break; - } - case ATH10K_PKTLOG_TYPE_TX_MSDU_ID: - break; - case ATH10K_PKTLOG_TYPE_TX_FRM_HDR: { - ath10k_process_ieee_hdr((void *)(hdr->payload)); - trace_ath10k_htt_pktlog(ar, hdr, sizeof(*hdr) + - __le16_to_cpu(hdr->size)); - break; - } - case ATH10K_PKTLOG_TYPE_RX_STAT: - case ATH10K_PKTLOG_TYPE_RC_FIND: - case ATH10K_PKTLOG_TYPE_RC_UPDATE: - case ATH10K_PKTLOG_TYPE_DBG_PRINT: - case ATH10K_PKTLOG_TYPE_TX_STAT: - case ATH10K_PKTLOG_TYPE_SW_EVENT: - trace_ath10k_htt_pktlog(ar, hdr, sizeof(*hdr) + - __le16_to_cpu(hdr->size)); - break; - case ATH10K_PKTLOG_TYPE_TX_VIRT_ADDR: { - u32 desc_id = (u32)*((u32 *)(hdr->payload)); - struct sk_buff *msdu; - - spin_lock_bh(&ar->htt.tx_lock); - msdu = ath10k_htt_tx_find_msdu_by_id(&ar->htt, desc_id); - - if (!msdu) { - ath10k_info(ar, - "Failed to get msdu, id: %d\n", - desc_id); - spin_unlock_bh(&ar->htt.tx_lock); - return; - } - ath10k_process_ieee_hdr((void *)msdu->data); - spin_unlock_bh(&ar->htt.tx_lock); - trace_ath10k_htt_pktlog(ar, hdr, sizeof(*hdr) + - __le16_to_cpu(hdr->size)); - break; - } - } -} - -int ath10k_rx_record_pktlog(struct ath10k *ar, struct sk_buff *skb) -{ - struct sk_buff *pktlog_skb; - struct ath_pktlog_hdr *pl_hdr; - struct ath_pktlog_rx_info *pktlog_rx_info; - struct htt_rx_desc *rx_desc = (void *)skb->data - sizeof(*rx_desc); - - if (!ar->debug.pktlog_filter) - return 0; - - pktlog_skb = dev_alloc_skb(sizeof(struct ath_pktlog_hdr) + - sizeof(struct htt_rx_desc) - - sizeof(struct htt_host_fw_desc_base)); - if (!pktlog_skb) - return -ENOMEM; - - pktlog_rx_info = (struct ath_pktlog_rx_info *)pktlog_skb->data; - pl_hdr = &pktlog_rx_info->pl_hdr; - - pl_hdr->flags = (1 << ATH10K_PKTLOG_FLG_FRM_TYPE_REMOTE_S); - pl_hdr->missed_cnt = 0; - pl_hdr->mac_id = 0; - pl_hdr->log_type = ATH10K_PKTLOG_TYPE_RX_STAT; - pl_hdr->flags |= ATH10K_PKTLOG_HDR_SIZE_16; - pl_hdr->size = sizeof(*rx_desc) - - sizeof(struct htt_host_fw_desc_base); - - pl_hdr->timestamp = - cpu_to_le32(rx_desc->ppdu_end.wcn3990.rx_pkt_end.phy_timestamp_1); - - pl_hdr->type_specific_data = 0xDEADAA; - memcpy((void *)pktlog_rx_info + sizeof(struct ath_pktlog_hdr), - (void *)rx_desc + sizeof(struct htt_host_fw_desc_base), - pl_hdr->size); - - ath10k_pktlog_process_rx(ar, pktlog_skb); - dev_kfree_skb_any(pktlog_skb); - return 0; -} - -static void ath10k_pktlog_htc_tx_complete(struct ath10k *ar, - struct sk_buff *skb) -{ - ath10k_info(ar, "PKTLOG htc completed\n"); -} - -int ath10k_pktlog_connect(struct ath10k *ar) -{ - int status; - struct ath10k_htc_svc_conn_req conn_req; - struct ath10k_htc_svc_conn_resp conn_resp; - - memset(&conn_req, 0, sizeof(conn_req)); - memset(&conn_resp, 0, sizeof(conn_resp)); - - conn_req.ep_ops.ep_tx_complete = ath10k_pktlog_htc_tx_complete; - conn_req.ep_ops.ep_rx_complete = ath10k_pktlog_process_rx; - conn_req.ep_ops.ep_tx_credits = NULL; - - /* connect to control service */ - conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_LOG_MSG; - status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp); - if (status) { - ath10k_warn(ar, "failed to connect to PKTLOG service: %d\n", - status); - return status; - } - - ar->debug.eid = conn_resp.eid; - - return 0; -} - int ath10k_debug_create(struct ath10k *ar) { ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data)); diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index eb47720bbf9141e389817b1b0d63d33b7fb0c1e1..f963391e35443803daf71d20362ba189878efa4f 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -57,84 +57,6 @@ enum ath10k_dbg_aggr_mode { ATH10K_DBG_AGGR_MODE_MAX, }; -#define IEEE80211_FC1_DIR_MASK 0x03 -#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ -#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ -#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ -#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ -#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ - -#define MAX_PKT_INFO_MSDU_ID 192 -#define MSDU_ID_INFO_ID_OFFSET \ - ((MAX_PKT_INFO_MSDU_ID >> 3) + 4) - -#define PKTLOG_MAX_TXCTL_WORDS 57 /* +2 words for bitmap */ -#define HTT_TX_MSDU_LEN_MASK 0xffff - -struct txctl_frm_hdr { - __le16 framectrl; /* frame control field from header */ - __le16 seqctrl; /* frame control field from header */ - __le16 bssid_tail; /* last two octets of bssid */ - __le16 sa_tail; /* last two octets of SA */ - __le16 da_tail; /* last two octets of DA */ - __le16 resvd; -} __packed; - -struct ath_pktlog_hdr { - __le16 flags; - __le16 missed_cnt; - u8 log_type; - u8 mac_id; - __le16 size; - __le32 timestamp; - __le32 type_specific_data; -} __packed; - -/* generic definitions for IEEE 802.11 frames */ -struct ieee80211_frame { - u8 i_fc[2]; - u8 i_dur[2]; - union { - struct { - u8 i_addr1[IEEE80211_ADDR_LEN]; - u8 i_addr2[IEEE80211_ADDR_LEN]; - u8 i_addr3[IEEE80211_ADDR_LEN]; - }; - u8 i_addr_all[3 * IEEE80211_ADDR_LEN]; - }; - u8 i_seq[2]; -} __packed; - -struct fw_pktlog_msdu_info { - __le32 num_msdu; - u8 bound_bmap[MAX_PKT_INFO_MSDU_ID >> 3]; - __le16 id[MAX_PKT_INFO_MSDU_ID]; -} __packed; - -struct ath_pktlog_txctl { - struct ath_pktlog_hdr hdr; - struct txctl_frm_hdr frm_hdr; - __le32 txdesc_ctl[PKTLOG_MAX_TXCTL_WORDS]; -} __packed; - -struct ath_pktlog_msdu_id { - struct ath_pktlog_hdr hdr; - struct fw_pktlog_msdu_info msdu_info; -} __packed; - -struct ath_pktlog_rx_info { - struct ath_pktlog_hdr pl_hdr; - struct rx_attention attention; - struct rx_frag_info frag_info; - struct rx_mpdu_start mpdu_start; - struct rx_msdu_start msdu_start; - struct rx_msdu_end msdu_end; - struct rx_mpdu_end mpdu_end; - struct rx_ppdu_start ppdu_start; - struct rx_ppdu_end ppdu_end; - u8 rx_hdr_status[RX_HTT_HDR_STATUS_LEN]; -} __packed; - /* FIXME: How to calculate the buffer size sanely? */ #define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024) #define ATH10K_DATAPATH_BUF_SIZE (1024 * 1024) @@ -164,7 +86,6 @@ struct ath10k_fw_crash_data * ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len); -int ath10k_rx_record_pktlog(struct ath10k *ar, struct sk_buff *skb); #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) void ath10k_debug_get_et_strings(struct ieee80211_hw *hw, @@ -177,7 +98,6 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, struct ethtool_stats *stats, u64 *data); void fill_datapath_stats(struct ath10k *ar, struct ieee80211_rx_status *status); size_t get_datapath_stat(char *buf, struct ath10k *ar); -int ath10k_pktlog_connect(struct ath10k *ar); #else static inline int ath10k_debug_start(struct ath10k *ar) { @@ -222,12 +142,6 @@ static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, { } -static inline int ath10k_rx_record_pktlog(struct ath10k *ar, - struct sk_buff *skb) -{ - return 0; -} - static inline struct ath10k_fw_crash_data * ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) { @@ -244,10 +158,6 @@ static inline size_t get_datapath_stat(char *buf, struct ath10k *ar) return 0; } -static inline int ath10k_pktlog_connect(struct ath10k *ar) -{ - return 0; -} #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) #define ath10k_debug_get_et_strings NULL diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 6377c4ef427c1b8b45e4823549d279f1dbe7d9fd..b0d6c26147310b78aec9dcf9c702c05b3c2e9253 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1745,21 +1745,16 @@ struct ath10k_htt { #define RX_HTT_HDR_STATUS_LEN 64 -struct htt_host_fw_desc_base { +/* This structure layout is programmed via rx ring setup + * so that FW knows how to transfer the rx descriptor to the host. + * Buffers like this are placed on the rx ring. */ +struct htt_rx_desc { union { /* This field is filled on the host using the msdu buffer * from htt_rx_indication */ struct fw_rx_desc_base fw_desc; u32 pad; } __packed; -}; - -/* This structure layout is programmed via rx ring setup - * so that FW knows how to transfer the rx descriptor to the host. - * Buffers like this are placed on the rx ring. - */ -struct htt_rx_desc { - struct htt_host_fw_desc_base fw_desc_base; struct { struct rx_attention attention; struct rx_frag_info frag_info; @@ -1852,7 +1847,5 @@ int ath10k_htt_tx(struct ath10k_htt *htt, void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar, struct sk_buff *skb); int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget); -struct sk_buff *ath10k_htt_tx_find_msdu_by_id(struct ath10k_htt *htt, - u16 msdu_id); #endif diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 635b8281b05567d3b0942280cfe8c8cd3aab3ba0..437ea2c192b3b4dc6a1cf0c32726ee05178c549e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -969,7 +969,6 @@ static void ath10k_process_rx(struct ath10k *ar, trace_ath10k_rx_hdr(ar, skb->data, skb->len); trace_ath10k_rx_payload(ar, skb->data, skb->len); - ath10k_rx_record_pktlog(ar, skb); ieee80211_rx_napi(ar->hw, NULL, skb, &ar->napi); } diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 6579eb2b410ce7300d20f4e80b099cad4cb981b9..1b59721a91ac3e37cd94ffcffac1baeebb3d3a4c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -218,27 +218,6 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) return ret; } -struct sk_buff *ath10k_htt_tx_find_msdu_by_id(struct ath10k_htt *htt, - u16 msdu_id) -{ - struct ath10k *ar; - struct sk_buff *ret; - - if (!htt) - return NULL; - - ar = htt->ar; - - lockdep_assert_held(&htt->tx_lock); - - ret = (struct sk_buff *)idr_find(&htt->pending_tx, msdu_id); - - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx find msdu by msdu_id %s\n", - !ret ? "Failed" : "Success"); - - return ret; -} - void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) { struct ath10k *ar = htt->ar; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 37479589b8e12ecbb6eac65ab234d4b46670a0c2..0f2422480c4e7450c32218787952ee3524deaee0 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -984,37 +984,4 @@ struct ath10k_shadow_reg_address { extern struct ath10k_shadow_reg_value wcn3990_shadow_reg_value; extern struct ath10k_shadow_reg_address wcn3990_shadow_reg_address; -#define ATH10K_PKTLOG_HDR_SIZE_16 0x8000 - -enum { - ATH10k_PKTLOG_FLG_FRM_TYPE_LOCAL_S = 0, - ATH10K_PKTLOG_FLG_FRM_TYPE_REMOTE_S, - ATH10K_PKTLOG_FLG_FRM_TYPE_CLONE_S, - ATH10K_PKTLOG_FLG_FRM_TYPE_CBF_S, - ATH10K_PKTLOG_FLG_FRM_TYPE_UNKNOWN_S -}; - -enum ath10k_pktlog_type { - ATH10K_PKTLOG_TYPE_TX_CTRL = 1, - ATH10K_PKTLOG_TYPE_TX_STAT, - ATH10K_PKTLOG_TYPE_TX_MSDU_ID, - ATH10K_PKTLOG_TYPE_TX_FRM_HDR, - ATH10K_PKTLOG_TYPE_RX_STAT, - ATH10K_PKTLOG_TYPE_RC_FIND, - ATH10K_PKTLOG_TYPE_RC_UPDATE, - ATH10K_PKTLOG_TYPE_TX_VIRT_ADDR, - ATH10K_PKTLOG_TYPE_DBG_PRINT, - ATH10K_PKTLOG_TYPE_SW_EVENT, - ATH10K_PKTLOG_TYPE_MAX, -}; - -struct ath10k_pktlog_hdr { - __le16 flags; - __le16 missed_cnt; - __le16 log_type; - __le16 size; - __le32 timestamp; - u8 payload[0]; -} __packed; - #endif /* _HW_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 01175d94adcaf51e92c7f159d6f54362a6a3a0f4..e430bab869a83de0700246b09a9922b2c25bd56d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -667,36 +667,6 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, *def = &conf->def; } -static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) -{ - int ret; - unsigned long time_left; - - lockdep_assert_held(&ar->conf_mutex); - - ret = ath10k_wmi_peer_delete(ar, vdev_id, addr); - if (ret) - return ret; - - ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr); - if (ret) - return ret; - - if (QCA_REV_WCN3990(ar)) { - time_left = wait_for_completion_timeout(&ar->peer_delete_done, - 50 * HZ); - - if (time_left == 0) { - ath10k_warn(ar, "Timeout in receiving peer delete response\n"); - return -ETIMEDOUT; - } - } - - ar->num_peers--; - - return 0; -} - static int ath10k_peer_create(struct ath10k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -741,7 +711,7 @@ static int ath10k_peer_create(struct ath10k *ar, spin_unlock_bh(&ar->data_lock); ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n", addr, vdev_id); - ath10k_peer_delete(ar, vdev_id, addr); + ath10k_wmi_peer_delete(ar, vdev_id, addr); return -ENOENT; } @@ -809,6 +779,36 @@ static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); } +static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) +{ + int ret; + unsigned long time_left; + + lockdep_assert_held(&ar->conf_mutex); + + ret = ath10k_wmi_peer_delete(ar, vdev_id, addr); + if (ret) + return ret; + + ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr); + if (ret) + return ret; + + if (QCA_REV_WCN3990(ar)) { + time_left = wait_for_completion_timeout(&ar->peer_delete_done, + 50 * HZ); + + if (time_left == 0) { + ath10k_warn(ar, "Timeout in receiving peer delete response\n"); + return -ETIMEDOUT; + } + } + + ar->num_peers--; + + return 0; +} + static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) { struct ath10k_peer *peer, *tmp; @@ -4507,13 +4507,6 @@ static int ath10k_start(struct ieee80211_hw *hw) goto err_core_stop; } - param = ar->wmi.pdev_param->idle_ps_config; - ret = ath10k_wmi_pdev_set_param(ar, param, 1); - if (ret) { - ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret); - goto err_core_stop; - } - if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) { ret = ath10k_wmi_adaptive_qcs(ar, true); if (ret) { @@ -5101,7 +5094,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, err_peer_delete: if (arvif->vdev_type == WMI_VDEV_TYPE_AP || arvif->vdev_type == WMI_VDEV_TYPE_IBSS) - ath10k_peer_delete(ar, arvif->vdev_id, vif->addr); + ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr); err_vdev_delete: ath10k_wmi_vdev_delete(ar, arvif->vdev_id); @@ -5157,8 +5150,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, if (arvif->vdev_type == WMI_VDEV_TYPE_AP || arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { - ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, - vif->addr); + ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id, + vif->addr); if (ret) ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n", arvif->vdev_id, ret); @@ -5479,8 +5472,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct cfg80211_scan_request *req = &hw_req->req; struct wmi_start_scan_arg arg; - const u8 *ptr; - int ret = 0, ie_skip_len = 0; + int ret = 0; int i; mutex_lock(&ar->conf_mutex); @@ -5512,16 +5504,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.scan_id = ATH10K_SCAN_ID; if (req->ie_len) { - if (QCA_REV_WCN3990(ar)) { - ptr = req->ie; - while (ptr[0] == WLAN_EID_SUPP_RATES || - ptr[0] == WLAN_EID_EXT_SUPP_RATES) { - ie_skip_len = ptr[1] + 2; - ptr += ie_skip_len; - } - } - arg.ie_len = req->ie_len - ie_skip_len; - memcpy(arg.ie, req->ie + ie_skip_len, arg.ie_len); + arg.ie_len = req->ie_len; + memcpy(arg.ie, req->ie, arg.ie_len); } if (req->n_ssids) { @@ -5530,11 +5514,6 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.ssids[i].len = req->ssids[i].ssid_len; arg.ssids[i].ssid = req->ssids[i].ssid; } - if (QCA_REV_WCN3990(ar)) { - arg.scan_ctrl_flags &= - ~(WMI_SCAN_ADD_BCAST_PROBE_REQ | - WMI_SCAN_CHAN_STAT_EVENT); - } } else { arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; } @@ -6433,13 +6412,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, arg.dwell_time_passive = scan_time_msec; arg.max_scan_time = scan_time_msec; arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; - if (QCA_REV_WCN3990(ar)) { - arg.scan_ctrl_flags &= ~(WMI_SCAN_FILTER_PROBE_REQ | - WMI_SCAN_CHAN_STAT_EVENT | - WMI_SCAN_ADD_BCAST_PROBE_REQ); - } else { - arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; - } + arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; arg.burst_duration_ms = duration; ret = ath10k_start_scan(ar, &arg); @@ -7195,25 +7168,12 @@ ath10k_mac_update_vif_chan(struct ath10k *ar, if (WARN_ON(!arvif->is_up)) continue; - if (QCA_REV_WCN3990(ar)) { - /* In the case of wcn3990 WLAN module we send - * vdev restart only, no need to send vdev down. - */ - ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); - if (ret) { - ath10k_warn(ar, - "failed to restart vdev %d: %d\n", - arvif->vdev_id, ret); - continue; - } - } else { - ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); - if (ret) { - ath10k_warn(ar, "failed to down vdev %d: %d\n", - arvif->vdev_id, ret); - continue; - } + ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); + if (ret) { + ath10k_warn(ar, "failed to down vdev %d: %d\n", + arvif->vdev_id, ret); + continue; } } @@ -7244,17 +7204,11 @@ ath10k_mac_update_vif_chan(struct ath10k *ar, ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", ret); - if (!QCA_REV_WCN3990(ar)) { - /* In case of other than wcn3990 WLAN module we - * send vdev down and vdev restart to the firmware. - */ - - ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); - if (ret) { - ath10k_warn(ar, "failed to restart vdev %d: %d\n", - arvif->vdev_id, ret); - continue; - } + ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); + if (ret) { + ath10k_warn(ar, "failed to restart vdev %d: %d\n", + arvif->vdev_id, ret); + continue; } ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, @@ -7849,6 +7803,10 @@ static const struct ieee80211_iface_limit ath10k_wcn3990_if_limit[] = { BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO), }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, }; static const struct ieee80211_iface_limit ath10k_wcn3990_qcs_if_limit[] = { @@ -7868,6 +7826,10 @@ static const struct ieee80211_iface_limit ath10k_wcn3990_qcs_if_limit[] = { #endif BIT(NL80211_IFTYPE_P2P_GO), }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, }; static const struct ieee80211_iface_limit ath10k_wcn3990_if_limit_ibss[] = { @@ -8041,10 +8003,6 @@ int ath10k_mac_register(struct ath10k *ar) BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); - if (QCA_REV_WCN3990(ar)) - ar->hw->wiphy->interface_modes &= - ~BIT(NL80211_IFTYPE_P2P_DEVICE); - ieee80211_hw_set(ar->hw, SIGNAL_DBM); ieee80211_hw_set(ar->hw, SUPPORTS_PS); ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index ca77861c43206c35fe213ae089b0eed11ffec67c..9e607b2fa2d4f0c60e9bac384cdd780c384aec9a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3139,7 +3139,7 @@ int ath10k_pci_setup_resource(struct ath10k *ar) setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, (unsigned long)ar); - if (QCA_REV_6174(ar) || QCA_REV_9377(ar)) + if (QCA_REV_6174(ar)) ath10k_pci_override_ce_config(ar); ret = ath10k_pci_alloc_pipes(ar); diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index dd310d5a7028eef3be256fd4ba181f9fc5aa3057..10223605b027ed0c05977bee59e66fdacd65ec71 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -719,7 +719,6 @@ static int ath10k_snoc_driver_event_server_exit(struct ath10k *ar) atomic_set(&qmi_cfg->fw_ready, 0); qmi_cfg->msa_ready = false; atomic_set(&qmi_cfg->server_connected, 0); - qmi_handle_destroy(qmi_cfg->wlfw_clnt); return 0; } @@ -897,6 +896,5 @@ void ath10k_snoc_stop_qmi_service(struct ath10k *ar) WLFW_SERVICE_INS_ID_V01, &qmi_cfg->wlfw_clnt_nb); destroy_workqueue(qmi_cfg->event_wq); - qmi_handle_destroy(qmi_cfg->wlfw_clnt); qmi_cfg = NULL; } diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index c42d7eebf4652b0c1e38b8e48cbc308f42d99f43..9406b6f71a6bdc2fe6bb064511259be54f23d503 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "core.h" #include "debug.h" #include "hif.h" @@ -27,8 +26,6 @@ #include "qmi.h" #include #include -#include -#include #define WCN3990_MAX_IRQ 12 @@ -50,7 +47,6 @@ const char *ce_name[WCN3990_MAX_IRQ] = { #define ATH10K_SNOC_TARGET_WAIT 3000 #define ATH10K_SNOC_NUM_WARM_RESET_ATTEMPTS 3 #define SNOC_HIF_POWER_DOWN_DELAY 30 -#define ATH10K_MAX_PROP_SIZE 32 static void ath10k_snoc_buffer_cleanup(struct ath10k *ar); static int ath10k_snoc_request_irq(struct ath10k *ar); @@ -111,8 +107,8 @@ static struct ce_attr host_ce_config_wlan[] = { { .flags = CE_ATTR_FLAGS, .src_nentries = 0, - .src_sz_max = 0, - .dest_nentries = 0, + .src_sz_max = 512, + .dest_nentries = 512, .recv_cb = ath10k_snoc_htt_rx_cb, }, @@ -779,6 +775,9 @@ static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar, } } + if (WARN_ON(!ul_set || !dl_set)) + return -ENOENT; + return 0; } @@ -959,13 +958,9 @@ static int ath10k_snoc_init_pipes(struct ath10k *ar) static void ath10k_snoc_hif_power_down(struct ath10k *ar) { - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); msleep(SNOC_HIF_POWER_DOWN_DELAY); - - if (!atomic_read(&ar_snoc->pm_ops_inprogress)) - ath10k_snoc_qmi_wlan_disable(ar); + ath10k_snoc_qmi_wlan_disable(ar); } int ath10k_snoc_get_ce_id(struct ath10k *ar, int irq) @@ -1149,18 +1144,10 @@ static int ath10k_snoc_claim(struct ath10k *ar) static int ath10k_snoc_hif_power_up(struct ath10k *ar) { int ret; - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n", __func__, ar->state); - if (atomic_read(&ar_snoc->pm_ops_inprogress)) { - ath10k_dbg(ar, ATH10K_DBG_SNOC, - "%s: WLAN OFF CMD Reset on PM Resume\n", __func__); - ath10k_snoc_qmi_wlan_disable(ar); - atomic_set(&ar_snoc->pm_ops_inprogress, 0); - } - if (ar->state == ATH10K_STATE_ON || test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { ret = ath10k_snoc_bus_configure(ar); @@ -1224,353 +1211,6 @@ out: return ret; } -static -int ath10k_snoc_pm_notifier(struct notifier_block *nb, - unsigned long pm_event, void *data) -{ - struct ath10k_snoc *ar_snoc = - container_of(nb, struct ath10k_snoc, pm_notifier); - struct ath10k *ar = ar_snoc->ar; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, - "%s: PM Event: %lu\n", __func__, pm_event); - - switch (pm_event) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - case PM_RESTORE_PREPARE: - case PM_POST_RESTORE: - atomic_set(&ar_snoc->pm_ops_inprogress, 1); - break; - default: - break; - } - - return NOTIFY_DONE; -} - -static int ath10k_get_vreg_info(struct ath10k *ar, struct device *dev, - struct ath10k_wcn3990_vreg_info *vreg_info) -{ - int ret = 0; - char prop_name[ATH10K_MAX_PROP_SIZE]; - struct regulator *reg; - const __be32 *prop; - int len = 0; - int i; - - reg = devm_regulator_get_optional(dev, vreg_info->name); - if (PTR_ERR(reg) == -EPROBE_DEFER) { - ath10k_err(ar, "EPROBE_DEFER for regulator: %s\n", - vreg_info->name); - ret = PTR_ERR(reg); - goto out; - } - - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - - if (vreg_info->required) { - ath10k_err(ar, "Regulator %s doesn't exist: %d\n", - vreg_info->name, ret); - goto out; - } else { - ath10k_dbg(ar, ATH10K_DBG_SNOC, - "Optional regulator %s doesn't exist: %d\n", - vreg_info->name, ret); - goto done; - } - } - - vreg_info->reg = reg; - - snprintf(prop_name, ATH10K_MAX_PROP_SIZE, - "qcom,%s-config", vreg_info->name); - - prop = of_get_property(dev->of_node, prop_name, &len); - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "Got regulator cfg,prop: %s, len: %d\n", - prop_name, len); - - if (!prop || len < (2 * sizeof(__be32))) { - ath10k_dbg(ar, ATH10K_DBG_SNOC, "Property %s %s\n", prop_name, - prop ? "invalid format" : "doesn't exist"); - goto done; - } - - for (i = 0; (i * sizeof(__be32)) < len; i++) { - switch (i) { - case 0: - vreg_info->min_v = be32_to_cpup(&prop[0]); - break; - case 1: - vreg_info->max_v = be32_to_cpup(&prop[1]); - break; - case 2: - vreg_info->load_ua = be32_to_cpup(&prop[2]); - break; - case 3: - vreg_info->settle_delay = be32_to_cpup(&prop[3]); - break; - default: - ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s, ignoring val %d\n", - prop_name, i); - break; - } - } - -done: - ath10k_dbg(ar, ATH10K_DBG_SNOC, - "vreg: %s, min_v: %u, max_v: %u, load: %u, delay: %lu\n", - vreg_info->name, vreg_info->min_v, vreg_info->max_v, - vreg_info->load_ua, vreg_info->settle_delay); - - return 0; - -out: - return ret; -} - -static int ath10k_get_clk_info(struct ath10k *ar, struct device *dev, - struct ath10k_wcn3990_clk_info *clk_info) -{ - struct clk *handle; - int ret = 0; - - handle = devm_clk_get(dev, clk_info->name); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - if (clk_info->required) { - ath10k_err(ar, "Clock %s isn't available: %d\n", - clk_info->name, ret); - goto out; - } else { - ath10k_dbg(ar, ATH10K_DBG_SNOC, "Ignoring clk %s: %d\n", - clk_info->name, - ret); - ret = 0; - goto out; - } - } - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "Clock: %s, freq: %u\n", - clk_info->name, clk_info->freq); - - clk_info->handle = handle; -out: - return ret; -} - -static int ath10k_wcn3990_vreg_on(struct ath10k *ar) -{ - int ret = 0; - struct ath10k_wcn3990_vreg_info *vreg_info; - int i; - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - - for (i = 0; i < ATH10K_WCN3990_VREG_INFO_SIZE; i++) { - vreg_info = &ar_snoc->vreg[i]; - - if (!vreg_info->reg) - continue; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "Regulator %s being enabled\n", - vreg_info->name); - - ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v, - vreg_info->max_v); - if (ret) { - ath10k_err(ar, - "vreg %s, set failed:min:%u,max:%u,ret: %d\n", - vreg_info->name, vreg_info->min_v, - vreg_info->max_v, ret); - break; - } - - if (vreg_info->load_ua) { - ret = regulator_set_load(vreg_info->reg, - vreg_info->load_ua); - if (ret < 0) { - ath10k_err(ar, - "Reg %s, can't set load:%u,ret: %d\n", - vreg_info->name, - vreg_info->load_ua, ret); - break; - } - } - - ret = regulator_enable(vreg_info->reg); - if (ret) { - ath10k_err(ar, "Regulator %s, can't enable: %d\n", - vreg_info->name, ret); - break; - } - - if (vreg_info->settle_delay) - udelay(vreg_info->settle_delay); - } - - if (!ret) - return 0; - - for (; i >= 0; i--) { - vreg_info = &ar_snoc->vreg[i]; - - if (!vreg_info->reg) - continue; - - regulator_disable(vreg_info->reg); - regulator_set_load(vreg_info->reg, 0); - regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v); - } - - return ret; -} - -static int ath10k_wcn3990_vreg_off(struct ath10k *ar) -{ - int ret = 0; - struct ath10k_wcn3990_vreg_info *vreg_info; - int i; - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - - for (i = ATH10K_WCN3990_VREG_INFO_SIZE - 1; i >= 0; i--) { - vreg_info = &ar_snoc->vreg[i]; - - if (!vreg_info->reg) - continue; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "Regulator %s being disabled\n", - vreg_info->name); - - ret = regulator_disable(vreg_info->reg); - if (ret) - ath10k_err(ar, "Regulator %s, can't disable: %d\n", - vreg_info->name, ret); - - ret = regulator_set_load(vreg_info->reg, 0); - if (ret < 0) - ath10k_err(ar, "Regulator %s, can't set load: %d\n", - vreg_info->name, ret); - - ret = regulator_set_voltage(vreg_info->reg, 0, - vreg_info->max_v); - if (ret) - ath10k_err(ar, "Regulator %s, can't set voltage: %d\n", - vreg_info->name, ret); - } - - return ret; -} - -static int ath10k_wcn3990_clk_init(struct ath10k *ar) -{ - struct ath10k_wcn3990_clk_info *clk_info; - int i; - int ret = 0; - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - - for (i = 0; i < ATH10K_WCN3990_CLK_INFO_SIZE; i++) { - clk_info = &ar_snoc->clk[i]; - - if (!clk_info->handle) - continue; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "Clock %s being enabled\n", - clk_info->name); - - if (clk_info->freq) { - ret = clk_set_rate(clk_info->handle, clk_info->freq); - - if (ret) { - ath10k_err(ar, "Clk %s,set err: %u,ret: %d\n", - clk_info->name, clk_info->freq, - ret); - break; - } - } - - ret = clk_prepare_enable(clk_info->handle); - if (ret) { - ath10k_err(ar, "Clock %s, can't enable: %d\n", - clk_info->name, ret); - break; - } - } - - if (ret == 0) - return 0; - - for (; i >= 0; i--) { - clk_info = &ar_snoc->clk[i]; - - if (!clk_info->handle) - continue; - - clk_disable_unprepare(clk_info->handle); - } - - return ret; -} - -static int ath10k_wcn3990_clk_deinit(struct ath10k *ar) -{ - struct ath10k_wcn3990_clk_info *clk_info; - int i; - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - - for (i = 0; i < ATH10K_WCN3990_CLK_INFO_SIZE; i++) { - clk_info = &ar_snoc->clk[i]; - - if (!clk_info->handle) - continue; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "Clock %s being disabled\n", - clk_info->name); - - clk_disable_unprepare(clk_info->handle); - } - - return 0; -} - -static int ath10k_hw_power_on(struct ath10k *ar) -{ - int ret = 0; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "HW Power on\n"); - - ret = ath10k_wcn3990_vreg_on(ar); - if (ret) - goto out; - - ret = ath10k_wcn3990_clk_init(ar); - if (ret) - goto vreg_off; - - return ret; - -vreg_off: - ath10k_wcn3990_vreg_off(ar); -out: - return ret; -} - -static int ath10k_hw_power_off(struct ath10k *ar) -{ - int ret = 0; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "HW Power off\n"); - - ath10k_wcn3990_clk_deinit(ar); - - ret = ath10k_wcn3990_vreg_off(ar); - - return ret; -} - static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .tx_sg = ath10k_snoc_hif_tx_sg, .start = ath10k_snoc_hif_start, @@ -1598,7 +1238,6 @@ static int ath10k_snoc_probe(struct platform_device *pdev) enum ath10k_hw_rev hw_rev; struct device *dev; u32 chip_id; - u32 i; dev = &pdev->dev; hw_rev = ATH10K_HW_WCN3990; @@ -1632,43 +1271,22 @@ static int ath10k_snoc_probe(struct platform_device *pdev) setup_timer(&ar_snoc->rx_post_retry, ath10k_snoc_rx_replenish_retry, (unsigned long)ar); - memcpy(ar_snoc->vreg, vreg_cfg, sizeof(vreg_cfg)); - for (i = 0; i < ATH10K_WCN3990_VREG_INFO_SIZE; i++) { - ret = ath10k_get_vreg_info(ar, dev, &ar_snoc->vreg[i]); - if (ret) - goto err_core_destroy; - } - - memcpy(ar_snoc->clk, clk_cfg, sizeof(clk_cfg)); - for (i = 0; i < ATH10K_WCN3990_CLK_INFO_SIZE; i++) { - ret = ath10k_get_clk_info(ar, dev, &ar_snoc->clk[i]); - if (ret) - goto err_core_destroy; - } - - ret = ath10k_hw_power_on(ar); - if (ret) { - ath10k_err(ar, "failed to power on device: %d\n", ret); - goto err_stop_qmi_service; - } - ret = ath10k_snoc_claim(ar); if (ret) { ath10k_err(ar, "failed to claim device: %d\n", ret); - goto err_hw_power_off; + goto err_core_destroy; } - ret = ath10k_snoc_bus_configure(ar); if (ret) { ath10k_err(ar, "failed to configure bus: %d\n", ret); - goto err_hw_power_off; + goto err_core_destroy; } ret = ath10k_snoc_alloc_pipes(ar); if (ret) { ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", ret); - goto err_hw_power_off; + goto err_core_destroy; } netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll, @@ -1691,9 +1309,6 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ath10k_snoc_modem_ssr_register_notifier(ar); ath10k_snoc_pd_restart_enable(ar); - ar_snoc->pm_notifier.notifier_call = ath10k_snoc_pm_notifier; - register_pm_notifier(&ar_snoc->pm_notifier); - ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 probed\n", __func__); return 0; @@ -1704,12 +1319,6 @@ err_free_irq: err_free_pipes: ath10k_snoc_free_pipes(ar); -err_hw_power_off: - ath10k_hw_power_off(ar); - -err_stop_qmi_service: - ath10k_snoc_stop_qmi_service(ar); - err_core_destroy: ath10k_core_destroy(ar); @@ -1729,7 +1338,6 @@ static int ath10k_snoc_remove(struct platform_device *pdev) ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 removed\n", __func__); - unregister_pm_notifier(&ar_snoc->pm_notifier); ath10k_core_unregister(ar); ath10k_snoc_pdr_unregister_notifier(ar); ath10k_snoc_modem_ssr_unregister_notifier(ar); @@ -1737,7 +1345,6 @@ static int ath10k_snoc_remove(struct platform_device *pdev) ath10k_snoc_release_resource(ar); ath10k_snoc_free_pipes(ar); ath10k_snoc_stop_qmi_service(ar); - ath10k_hw_power_off(ar); ath10k_core_destroy(ar); return 0; diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index a02cb2ad928e87124db6489b816685615f29db7f..7a223b1d3deda99da67da472c2450e6873b14342 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -17,7 +17,6 @@ #include "ce.h" #include "pci.h" #include "qmi.h" -#include #include #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 @@ -113,38 +112,6 @@ struct ath10k_snoc_ce_irq { u32 irq_line; }; -struct ath10k_wcn3990_vreg_info { - struct regulator *reg; - const char *name; - u32 min_v; - u32 max_v; - u32 load_ua; - unsigned long settle_delay; - bool required; -}; - -struct ath10k_wcn3990_clk_info { - struct clk *handle; - const char *name; - u32 freq; - bool required; -}; - -static struct ath10k_wcn3990_vreg_info vreg_cfg[] = { - {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, false}, - {NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false}, - {NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false}, - {NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false}, -}; - -#define ATH10K_WCN3990_VREG_INFO_SIZE ARRAY_SIZE(vreg_cfg) - -static struct ath10k_wcn3990_clk_info clk_cfg[] = { - {NULL, "cxo_ref_clk_pin", 0, false}, -}; - -#define ATH10K_WCN3990_CLK_INFO_SIZE ARRAY_SIZE(clk_cfg) - /* struct ath10k_snoc: SNOC info struct * @dev: device structure * @ar:ath10k base structure @@ -181,17 +148,13 @@ struct ath10k_snoc { u32 *vaddr_rri_on_ddr; bool is_driver_probed; struct notifier_block modem_ssr_nb; - struct notifier_block pm_notifier; void *modem_notify_handler; struct ath10k_service_notifier_context *service_notifier; struct notifier_block service_notifier_nb; int total_domains; struct notifier_block get_service_nb; atomic_t fw_crashed; - atomic_t pm_ops_inprogress; struct ath10k_snoc_qmi_config qmi_cfg; - struct ath10k_wcn3990_vreg_info vreg[ATH10K_WCN3990_VREG_INFO_SIZE]; - struct ath10k_wcn3990_clk_info clk[ATH10K_WCN3990_CLK_INFO_SIZE]; }; struct ath10k_event_pd_down_data { diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index c3100fcd80f25944663f247106e0b1cbfb72ebeb..129859255295594362ed9b72a1e4c78f7f0144da 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -31,8 +31,6 @@ struct wmi_ops { struct wmi_mgmt_rx_ev_arg *arg); int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb, struct wmi_ch_info_ev_arg *arg); - int (*pull_peer_delete_resp)(struct ath10k *ar, struct sk_buff *skb, - struct wmi_peer_delete_resp_ev_arg *arg); int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb, struct wmi_vdev_start_ev_arg *arg); int (*pull_peer_kick)(struct ath10k *ar, struct sk_buff *skb, @@ -247,16 +245,6 @@ ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb, return ar->wmi.ops->pull_mgmt_rx(ar, skb, arg); } -static inline int -ath10k_wmi_pull_peer_delete_resp(struct ath10k *ar, struct sk_buff *skb, - struct wmi_peer_delete_resp_ev_arg *arg) -{ - if (!ar->wmi.ops->pull_peer_delete_resp) - return -EOPNOTSUPP; - - return ar->wmi.ops->pull_peer_delete_resp(ar, skb, arg); -} - static inline int ath10k_wmi_pull_ch_info(struct ath10k *ar, struct sk_buff *skb, struct wmi_ch_info_ev_arg *arg) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index f5360444a083b148ea054c0aae97341895b73afa..888ab5ad37f1adb1f8af8aefd08dbf8d1aae97b5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -412,6 +412,15 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, return 0; } +static int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar, + struct sk_buff *skb) +{ + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TLV_PEER_DELETE_RESP_EVENTID\n"); + complete(&ar->peer_delete_done); + + return 0; +} + /***********/ /* TLV ops */ /***********/ @@ -648,34 +657,6 @@ static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar, return 0; } -static int ath10k_wmi_tlv_op_pull_peer_delete_ev( - struct ath10k *ar, struct sk_buff *skb, - struct wmi_peer_delete_resp_ev_arg *arg) -{ - const void **tb; - const struct wmi_peer_delete_resp_ev_arg *ev; - int ret; - - tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); - if (IS_ERR(tb)) { - ret = PTR_ERR(tb); - ath10k_warn(ar, "failed to parse tlv: %d\n", ret); - return ret; - } - - ev = tb[WMI_TLV_TAG_STRUCT_PEER_DELETE_RESP_EVENT]; - if (!ev) { - kfree(tb); - return -EPROTO; - } - - arg->vdev_id = ev->vdev_id; - arg->peer_addr = ev->peer_addr; - - kfree(tb); - return 0; -} - static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb, struct wmi_ch_info_ev_arg *arg) @@ -1553,7 +1534,11 @@ ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar, cmd->ie_len = __cpu_to_le32(arg->ie_len); cmd->num_probes = __cpu_to_le32(3); - if (!QCA_REV_WCN3990(ar)) { + if (QCA_REV_WCN3990(ar)) { + cmd->common.scan_ctrl_flags = ar->fw_flags->flags; + cmd->common.scan_ctrl_flags |= + __cpu_to_le32(WMI_SCAN_CHAN_STAT_EVENT); + } else { cmd->common.scan_ctrl_flags ^= __cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ); } @@ -3635,7 +3620,6 @@ static const struct wmi_ops wmi_tlv_ops = { .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev, .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev, .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev, - .pull_peer_delete_resp = ath10k_wmi_tlv_op_pull_peer_delete_ev, .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 500d1d8f441f1e4a2201b15f77eab516c9cc17f6..86b24c24d9f1a7ef104fe5e160414277ecbb9652 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -898,7 +898,6 @@ enum wmi_tlv_tag { WMI_TLV_TAG_STRUCT_HL_1_0_SVC_OFFSET = 176, WMI_TLV_TAG_STRUCT_MGMT_TX_CMD = 0x1A6, - WMI_TLV_TAG_STRUCT_PEER_DELETE_RESP_EVENT = 0x1C3, WMI_TLV_TAG_MAX }; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 86aedff096f697a0eab9e1a8e69a3e8fd8e2920e..d60e7fbb7e74fd9e4d406261d74ff3d5cc5d4481 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2269,24 +2269,6 @@ static bool ath10k_wmi_rx_is_decrypted(struct ath10k *ar, return true; } -int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar, - struct sk_buff *skb) -{ - int ret; - struct wmi_peer_delete_resp_ev_arg arg = {}; - - ret = ath10k_wmi_pull_peer_delete_resp(ar, skb, &arg); - if (ret) { - ath10k_warn(ar, "failed to parse peer delete resp: %d\n", ret); - dev_kfree_skb(skb); - return ret; - } - ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TLV_PEER_DELETE_RESP_EVENTID\n"); - complete(&ar->peer_delete_done); - - return 0; -} - int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_mgmt_rx_ev_arg arg = {}; @@ -6192,8 +6174,6 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar, | WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHANNEL | WMI_SCAN_EVENT_DEQUEUED; - if (QCA_REV_WCN3990(ar)) - arg->scan_ctrl_flags = ar->fw_flags->flags; arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT; arg->n_bssids = 1; arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index f59e5f86708b4206f91ab84c7dd97efd265ee1b7..9bd374910379fba4a91897386d1a8e97cf9f828d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2960,8 +2960,6 @@ struct wmi_start_scan_arg { /* Different FW scan engine may choose to bail out on errors. * Allow the driver to have influence over that. */ #define WMI_SCAN_CONTINUE_ON_ERROR 0x80 -/** add DS content in probe req frame */ -#define WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ 0x800 /* WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */ #define WMI_SCAN_CLASS_MASK 0xFF000000 @@ -6236,11 +6234,6 @@ struct wmi_scan_ev_arg { __le32 vdev_id; }; -struct wmi_peer_delete_resp_ev_arg { - __le32 vdev_id; - struct wmi_mac_addr peer_addr; -}; - struct wmi_mgmt_rx_ev_arg { __le32 channel; __le32 snr; @@ -6610,8 +6603,6 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg); int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb); -int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar, - struct sk_buff *skb); int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb); diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 111f22abe52e4f774120f3366f1394b8e1061e97..63bb7686b8115b773c5cf3ec3ed68cc584ed1eb9 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -345,12 +345,12 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, wil_dbg_wmi(wil, "Link status for CID %d: {\n" " MCS %d TSF 0x%016llx\n" - " BF status 0x%08x RSSI %d SQI %d%%\n" + " BF status 0x%08x SNR 0x%08x SQI %d%%\n" " Tx Tpt %d goodput %d Rx goodput %d\n" " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", cid, le16_to_cpu(reply.evt.bf_mcs), le64_to_cpu(reply.evt.tsf), reply.evt.status, - reply.evt.rssi, + le32_to_cpu(reply.evt.snr_val), reply.evt.sqi, le32_to_cpu(reply.evt.tx_tpt), le32_to_cpu(reply.evt.tx_goodput), @@ -384,11 +384,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, if (test_bit(wil_status_fwconnected, wil->status)) { sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); - if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, - wil->fw_capabilities)) - sinfo->signal = reply.evt.rssi; - else - sinfo->signal = reply.evt.sqi; + sinfo->signal = reply.evt.sqi; } return rc; @@ -964,7 +960,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true); - if (len < sizeof(struct ieee80211_hdr_3addr)) + if (len < sizeof(struct ieee80211_mgmt)) return -EINVAL; cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); @@ -1874,7 +1870,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz; - /* may change after reading FW capabilities */ + /* TODO: figure this out */ wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; wiphy->cipher_suites = wil_cipher_suites; diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 30c02e36e0b76e912e847c48e18da71e878bc38a..6eefb9e61ec452546aec8be26875de5c9b5179bf 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1027,7 +1027,6 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) " TSF = 0x%016llx\n" " TxMCS = %2d TxTpt = %4d\n" " SQI = %4d\n" - " RSSI = %4d\n" " Status = 0x%08x %s\n" " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n" " Goodput(rx:tx) %4d:%4d\n" @@ -1037,7 +1036,6 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) le16_to_cpu(reply.evt.bf_mcs), le32_to_cpu(reply.evt.tx_tpt), reply.evt.sqi, - reply.evt.rssi, status, wil_bfstatus_str(status), le16_to_cpu(reply.evt.my_rx_sector), le16_to_cpu(reply.evt.my_tx_sector), diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 7a33792913a3a7006bbff8b0cf2794e68630c712..e01acac88825d895dbae09fe67f6e21b0ad3fbd2 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -124,19 +124,24 @@ static int fw_ignore_section(struct wil6210_priv *wil, const void *data, return 0; } +static int fw_handle_comment(struct wil6210_priv *wil, const void *data, + size_t size) +{ + wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true); + + return 0; +} + static int -fw_handle_comment(struct wil6210_priv *wil, const void *data, - size_t size) +fw_handle_capabilities(struct wil6210_priv *wil, const void *data, + size_t size) { const struct wil_fw_record_capabilities *rec = data; size_t capa_size; if (size < sizeof(*rec) || - le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) { - wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, - data, size, true); + le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) return 0; - } capa_size = size - offsetof(struct wil_fw_record_capabilities, capabilities); @@ -417,7 +422,7 @@ static const struct { int (*parse_handler)(struct wil6210_priv *wil, const void *data, size_t size); } wil_fw_handlers[] = { - {wil_fw_type_comment, fw_handle_comment, fw_handle_comment}, + {wil_fw_type_comment, fw_handle_comment, fw_handle_capabilities}, {wil_fw_type_data, fw_handle_data, fw_ignore_section}, {wil_fw_type_fill, fw_handle_fill, fw_ignore_section}, /* wil_fw_type_action */ @@ -512,7 +517,7 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name, rc = request_firmware(&fw, name, wil_to_dev(wil)); if (rc) { - wil_err_fw(wil, "Failed to load firmware %s rc %d\n", name, rc); + wil_err_fw(wil, "Failed to load firmware %s\n", name); return rc; } wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 64ab13c02ff50b98b5711bd6243d1ca26abeb32c..78091b7910c76145f8e975daeecd3a892be060f7 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -761,8 +761,6 @@ static void wil_collect_fw_info(struct wil6210_priv *wil) u8 retry_short; int rc; - wil_refresh_fw_capabilities(wil); - rc = wmi_get_mgmt_retry(wil, &retry_short); if (!rc) { wiphy->retry_short = retry_short; @@ -770,25 +768,6 @@ static void wil_collect_fw_info(struct wil6210_priv *wil) } } -void wil_refresh_fw_capabilities(struct wil6210_priv *wil) -{ - struct wiphy *wiphy = wil_to_wiphy(wil); - - wil->keep_radio_on_during_sleep = - wil->platform_ops.keep_radio_on_during_sleep && - wil->platform_ops.keep_radio_on_during_sleep( - wil->platform_handle) && - test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities); - - wil_info(wil, "keep_radio_on_during_sleep (%d)\n", - wil->keep_radio_on_during_sleep); - - if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities)) - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - else - wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; -} - void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) { le32_to_cpus(&r->base); @@ -1082,14 +1061,14 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } - wil_collect_fw_info(wil); - if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT) wil_ps_update(wil, wil->ps_profile); if (wil->tt_data_set) wmi_set_tt_cfg(wil, &wil->tt_data); + wil_collect_fw_info(wil); + if (wil->platform_ops.notify) { rc = wil->platform_ops.notify(wil->platform_handle, WIL_PLATFORM_EVT_FW_RDY); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 5432b319a52e712d7e7a9fabddce6b516ddbe0cc..e91cddbacf2491eaa7dfc38f190ba34f61428a8b 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -84,7 +84,6 @@ void wil_set_capabilities(struct wil6210_priv *wil) /* extract FW capabilities from file without loading the FW */ wil_request_firmware(wil, wil->wil_fw_name, false); - wil_refresh_fw_capabilities(wil); } void wil_disable_irq(struct wil6210_priv *wil) @@ -287,6 +286,15 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil_set_capabilities(wil); wil6210_clear_irq(wil); + wil->keep_radio_on_during_sleep = + wil->platform_ops.keep_radio_on_during_sleep && + wil->platform_ops.keep_radio_on_during_sleep( + wil->platform_handle) && + test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities); + + wil_info(wil, "keep_radio_on_during_sleep (%d)\n", + wil->keep_radio_on_during_sleep); + /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c index b91bf51be7679be889d006a13fd0551dd13e1869..b4c4d09011b43073f8dd6b7f1fa99f7f416f8693 100644 --- a/drivers/net/wireless/ath/wil6210/sysfs.c +++ b/drivers/net/wireless/ath/wil6210/sysfs.c @@ -291,8 +291,6 @@ int wil6210_sysfs_init(struct wil6210_priv *wil) return err; } - kobject_uevent(&dev->kobj, KOBJ_CHANGE); - return 0; } @@ -301,5 +299,4 @@ void wil6210_sysfs_remove(struct wil6210_priv *wil) struct device *dev = wil_to_dev(wil); sysfs_remove_group(&dev->kobj, &wil6210_attribute_group); - kobject_uevent(&dev->kobj, KOBJ_CHANGE); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 8934f768399a43a6e7dec2110f99de6c3966a27a..9525f521d21513cae4d59f49e5aa714bb55ebc98 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -861,7 +861,6 @@ int wil_up(struct wil6210_priv *wil); int __wil_up(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil); int __wil_down(struct wil6210_priv *wil); -void wil_refresh_fw_capabilities(struct wil6210_priv *wil); void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); void wil_set_ethtoolops(struct net_device *ndev); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 61f629c94bbbddeca84f74b237de480be90a88c0..fba0d6a79ae22be0b2ebf67a0a7c4ea539f4f867 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -382,15 +382,12 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) ch_no = data->info.channel + 1; freq = ieee80211_channel_to_frequency(ch_no, IEEE80211_BAND_60GHZ); channel = ieee80211_get_channel(wiphy, freq); - if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities)) - signal = 100 * data->info.rssi; - else - signal = data->info.sqi; + signal = data->info.sqi; d_status = le16_to_cpu(data->info.status); fc = rx_mgmt_frame->frame_control; - wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d RSSI %d SQI %d%%\n", - data->info.channel, data->info.mcs, data->info.rssi, + wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d SNR %d SQI %d%%\n", + data->info.channel, data->info.mcs, data->info.snr, data->info.sqi); wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, le16_to_cpu(fc)); diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 4e31c2fd1fc66b334eed44883930fab9be1896e8..256f63c57da0b7b16a4e03ea9d9c9b30c73bb2a8 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -60,7 +60,6 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_WMI_ONLY = 5, WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7, WMI_FW_CAPABILITY_D3_SUSPEND = 8, - WMI_FW_CAPABILITY_RSSI_REPORTING = 12, WMI_FW_CAPABILITY_MAX, }; @@ -1307,8 +1306,7 @@ struct wmi_notify_req_done_event { /* beamforming status, 0: fail; 1: OK; 2: retrying */ __le32 status; __le64 tsf; - s8 rssi; - u8 reserved0[3]; + __le32 snr_val; __le32 tx_tpt; __le32 tx_goodput; __le32 rx_goodput; @@ -1604,7 +1602,7 @@ struct wmi_get_ssid_event { /* wmi_rx_mgmt_info */ struct wmi_rx_mgmt_info { u8 mcs; - s8 rssi; + s8 snr; u8 range; u8 sqi; __le16 stype; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index da5826d788d6fff05c82f778813e90235e02047d..70a6985334d5b518f517848b5f969cec80b3c5f2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -4472,11 +4472,6 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, GFP_KERNEL); } else if (ieee80211_is_action(mgmt->frame_control)) { - if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) { - brcmf_err("invalid action frame length\n"); - err = -EINVAL; - goto exit; - } af_params = kzalloc(sizeof(*af_params), GFP_KERNEL); if (af_params == NULL) { brcmf_err("unable to allocate frame\n"); diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig index 6faf9f1ef5d01cc4a49d1ffe24b9a144f501cb60..8946f65df716ab770e7ab46977f43f7b89cdbbfa 100644 --- a/drivers/net/wireless/cnss/Kconfig +++ b/drivers/net/wireless/cnss/Kconfig @@ -56,9 +56,6 @@ config CLD_LL_CORE select WEXT_PRIV select WEXT_SPY select WIRELESS_EXT - select CRYPTO - select CRYPTO_HASH - select CRYPTO_BLKCIPHER ---help--- This section contains the necessary modules needed to enable the core WLAN driver for Qualcomm QCA6174 chipset. @@ -76,7 +73,7 @@ config CNSS_SECURE_FW config BUS_AUTO_SUSPEND bool "Enable/Disable Runtime PM support for PCIe based WLAN Drivers" - depends on CNSS || CNSS2 + depends on CNSS depends on PCI ---help--- Runtime Power Management is supported for PCIe based WLAN Drivers. diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index af92f00ca56ec2fa58e303af4d91b0aa416afd1f..22c59d8c3c451128559341a80e236f5e05340f73 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -83,7 +83,6 @@ #define QCA6180_DEVICE_ID (0x0041) #define QCA6180_REV_ID_OFFSET (0x08) -#define WLAN_EN_VREG_NAME "vdd-wlan-en" #define WLAN_VREG_NAME "vdd-wlan" #define WLAN_VREG_IO_NAME "vdd-wlan-io" #define WLAN_VREG_XTAL_NAME "vdd-wlan-xtal" @@ -115,8 +114,6 @@ #define WLAN_VREG_SP2T_MIN 2700000 #define POWER_ON_DELAY 2 -#define WLAN_VREG_IO_DELAY_MIN 100 -#define WLAN_VREG_IO_DELAY_MAX 1000 #define WLAN_ENABLE_DELAY 10 #define WLAN_RECOVERY_DELAY 1 #define PCIE_ENABLE_DELAY 100 @@ -137,6 +134,7 @@ static DEFINE_SPINLOCK(pci_link_down_lock); #define FW_IMAGE_MISSION (0x02) #define FW_IMAGE_BDATA (0x03) #define FW_IMAGE_PRINT (0x04) +#define FW_SETUP_DELAY 2000 #define SEG_METADATA (0x01) #define SEG_NON_PAGED (0x02) @@ -157,7 +155,6 @@ struct cnss_wlan_gpio_info { }; struct cnss_wlan_vreg_info { - struct regulator *wlan_en_reg; struct regulator *wlan_reg; struct regulator *soc_swreg; struct regulator *ant_switch; @@ -240,7 +237,6 @@ static struct cnss_data { dma_addr_t smmu_iova_start; size_t smmu_iova_len; struct cnss_wlan_vreg_info vreg_info; - bool wlan_en_vreg_support; struct cnss_wlan_gpio_info gpio_info; bool pcie_link_state; bool pcie_link_down_ind; @@ -278,8 +274,10 @@ static struct cnss_data { u32 fw_dma_size; u32 fw_seg_count; struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS]; + atomic_t fw_store_in_progress; /* Firmware setup complete lock */ struct mutex fw_setup_stat_lock; + struct completion fw_setup_complete; void *bdata_cpu; dma_addr_t bdata_dma; u32 bdata_dma_size; @@ -296,17 +294,6 @@ module_param(pcie_link_down_panic, uint, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(pcie_link_down_panic, "Trigger kernel panic when PCIe link down is detected"); -static void cnss_put_wlan_enable_gpio(void) -{ - struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; - struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; - - if (penv->wlan_en_vreg_support) - regulator_put(vreg_info->wlan_en_reg); - else - gpio_free(gpio_info->num); -} - static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info) { int ret; @@ -320,6 +307,13 @@ static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info) } } + ret = regulator_enable(vreg_info->wlan_reg); + if (ret) { + pr_err("%s: regulator enable failed for WLAN power\n", + __func__); + goto error_enable; + } + if (vreg_info->wlan_reg_io) { ret = regulator_enable(vreg_info->wlan_reg_io); if (ret) { @@ -327,8 +321,6 @@ static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info) __func__); goto error_enable_reg_io; } - - usleep_range(WLAN_VREG_IO_DELAY_MIN, WLAN_VREG_IO_DELAY_MAX); } if (vreg_info->wlan_reg_xtal_aon) { @@ -349,13 +341,6 @@ static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info) } } - ret = regulator_enable(vreg_info->wlan_reg); - if (ret) { - pr_err("%s: regulator enable failed for WLAN power\n", - __func__); - goto error_enable; - } - if (vreg_info->wlan_reg_sp2t) { ret = regulator_enable(vreg_info->wlan_reg_sp2t); if (ret) { @@ -392,8 +377,6 @@ error_enable_ant_switch: if (vreg_info->wlan_reg_sp2t) regulator_disable(vreg_info->wlan_reg_sp2t); error_enable_reg_sp2t: - regulator_disable(vreg_info->wlan_reg); -error_enable: if (vreg_info->wlan_reg_xtal) regulator_disable(vreg_info->wlan_reg_xtal); error_enable_reg_xtal: @@ -403,6 +386,8 @@ error_enable_reg_xtal_aon: if (vreg_info->wlan_reg_io) regulator_disable(vreg_info->wlan_reg_io); error_enable_reg_io: + regulator_disable(vreg_info->wlan_reg); +error_enable: if (vreg_info->wlan_reg_core) regulator_disable(vreg_info->wlan_reg_core); error_enable_reg_core: @@ -440,13 +425,6 @@ static int cnss_wlan_vreg_off(struct cnss_wlan_vreg_info *vreg_info) } } - ret = regulator_disable(vreg_info->wlan_reg); - if (ret) { - pr_err("%s: regulator disable failed for WLAN power\n", - __func__); - goto error_disable; - } - if (vreg_info->wlan_reg_xtal) { ret = regulator_disable(vreg_info->wlan_reg_xtal); if (ret) { @@ -474,6 +452,13 @@ static int cnss_wlan_vreg_off(struct cnss_wlan_vreg_info *vreg_info) } } + ret = regulator_disable(vreg_info->wlan_reg); + if (ret) { + pr_err("%s: regulator disable failed for WLAN power\n", + __func__); + goto error_disable; + } + if (vreg_info->wlan_reg_core) { ret = regulator_disable(vreg_info->wlan_reg_core); if (ret) { @@ -590,25 +575,6 @@ static void cnss_wlan_gpio_set(struct cnss_wlan_gpio_info *info, bool state) info->name, info->state ? "enabled" : "disabled"); } -static int cnss_configure_wlan_en_gpio(bool state) -{ - int ret = 0; - struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; - struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; - - if (penv->wlan_en_vreg_support) { - if (state) - ret = regulator_enable(vreg_info->wlan_en_reg); - else - ret = regulator_disable(vreg_info->wlan_en_reg); - } else { - cnss_wlan_gpio_set(gpio_info, state); - } - - msleep(WLAN_ENABLE_DELAY); - return ret; -} - static int cnss_pinctrl_init(struct cnss_wlan_gpio_info *gpio_info, struct platform_device *pdev) { @@ -715,71 +681,14 @@ end: return ret; } -static int cnss_get_wlan_enable_gpio( - struct cnss_wlan_gpio_info *gpio_info, - struct platform_device *pdev) -{ - int ret = 0; - struct device *dev = &pdev->dev; - - if (!of_find_property(dev->of_node, gpio_info->name, NULL)) { - gpio_info->prop = false; - return -ENODEV; - } - - gpio_info->prop = true; - ret = of_get_named_gpio(dev->of_node, gpio_info->name, 0); - if (ret >= 0) { - gpio_info->num = ret; - } else { - if (ret == -EPROBE_DEFER) - pr_debug("get WLAN_EN GPIO probe defer\n"); - else - pr_err( - "can't get gpio %s ret %d", gpio_info->name, ret); - } - - ret = cnss_pinctrl_init(gpio_info, pdev); - if (ret) - pr_debug("%s: pinctrl init failed!\n", __func__); - - ret = cnss_wlan_gpio_init(gpio_info); - if (ret) - pr_err("gpio init failed\n"); - - return ret; -} - -static int cnss_get_wlan_bootstrap_gpio(struct platform_device *pdev) -{ - int ret = 0; - struct device_node *node = (&pdev->dev)->of_node; - - if (!of_find_property(node, WLAN_BOOTSTRAP_GPIO_NAME, NULL)) - return ret; - - penv->wlan_bootstrap_gpio = - of_get_named_gpio(node, WLAN_BOOTSTRAP_GPIO_NAME, 0); - if (penv->wlan_bootstrap_gpio > 0) { - ret = cnss_wlan_bootstrap_gpio_init(); - } else { - ret = penv->wlan_bootstrap_gpio; - pr_err( - "%s: Can't get GPIO %s, ret = %d", - __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret); - } - - return ret; -} - static int cnss_wlan_get_resources(struct platform_device *pdev) { int ret = 0; struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; - struct device_node *node = pdev->dev.of_node; - if (of_get_property(node, WLAN_VREG_CORE_NAME "-supply", NULL)) { + if (of_get_property(pdev->dev.of_node, + WLAN_VREG_CORE_NAME"-supply", NULL)) { vreg_info->wlan_reg_core = regulator_get(&pdev->dev, WLAN_VREG_CORE_NAME); if (IS_ERR(vreg_info->wlan_reg_core)) { @@ -809,7 +718,26 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) } } - if (of_get_property(node, WLAN_VREG_IO_NAME "-supply", NULL)) { + vreg_info->wlan_reg = regulator_get(&pdev->dev, WLAN_VREG_NAME); + + if (IS_ERR(vreg_info->wlan_reg)) { + if (PTR_ERR(vreg_info->wlan_reg) == -EPROBE_DEFER) + pr_err("%s: vreg probe defer\n", __func__); + else + pr_err("%s: vreg regulator get failed\n", __func__); + ret = PTR_ERR(vreg_info->wlan_reg); + goto err_reg_get; + } + + ret = regulator_enable(vreg_info->wlan_reg); + + if (ret) { + pr_err("%s: vreg initial vote failed\n", __func__); + goto err_reg_enable; + } + + if (of_get_property(pdev->dev.of_node, + WLAN_VREG_IO_NAME"-supply", NULL)) { vreg_info->wlan_reg_io = regulator_get(&pdev->dev, WLAN_VREG_IO_NAME); if (!IS_ERR(vreg_info->wlan_reg_io)) { @@ -827,34 +755,14 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) __func__); goto err_reg_io_enable; } - - usleep_range(WLAN_VREG_IO_DELAY_MIN, - WLAN_VREG_IO_DELAY_MAX); } } if (cnss_enable_xtal_ldo(pdev)) goto err_reg_xtal_enable; - vreg_info->wlan_reg = regulator_get(&pdev->dev, WLAN_VREG_NAME); - - if (IS_ERR(vreg_info->wlan_reg)) { - if (PTR_ERR(vreg_info->wlan_reg) == -EPROBE_DEFER) - pr_err("%s: vreg probe defer\n", __func__); - else - pr_err("%s: vreg regulator get failed\n", __func__); - ret = PTR_ERR(vreg_info->wlan_reg); - goto err_reg_get; - } - - ret = regulator_enable(vreg_info->wlan_reg); - - if (ret) { - pr_err("%s: vreg initial vote failed\n", __func__); - goto err_reg_enable; - } - - if (of_get_property(node, WLAN_VREG_SP2T_NAME "-supply", NULL)) { + if (of_get_property(pdev->dev.of_node, + WLAN_VREG_SP2T_NAME"-supply", NULL)) { vreg_info->wlan_reg_sp2t = regulator_get(&pdev->dev, WLAN_VREG_SP2T_NAME); if (!IS_ERR(vreg_info->wlan_reg_sp2t)) { @@ -875,7 +783,8 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) } } - if (of_get_property(node, WLAN_ANT_SWITCH_NAME "-supply", NULL)) { + if (of_get_property(pdev->dev.of_node, + WLAN_ANT_SWITCH_NAME "-supply", NULL)) { vreg_info->ant_switch = regulator_get(&pdev->dev, WLAN_ANT_SWITCH_NAME); if (!IS_ERR(vreg_info->ant_switch)) { @@ -905,10 +814,13 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) } } - if (of_find_property(node, "qcom,wlan-uart-access", NULL)) + if (of_find_property((&pdev->dev)->of_node, + "qcom,wlan-uart-access", NULL)) penv->cap.cap_flag |= CNSS_HAS_UART_ACCESS; - if (of_get_property(node, WLAN_SWREG_NAME "-supply", NULL)) { + if (of_get_property(pdev->dev.of_node, + WLAN_SWREG_NAME"-supply", NULL)) { + vreg_info->soc_swreg = regulator_get(&pdev->dev, WLAN_SWREG_NAME); if (IS_ERR(vreg_info->soc_swreg)) { @@ -931,41 +843,68 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) penv->cap.cap_flag |= CNSS_HAS_EXTERNAL_SWREG; } - penv->wlan_en_vreg_support = - of_property_read_bool(node, "qcom,wlan-en-vreg-support"); - if (penv->wlan_en_vreg_support) { - vreg_info->wlan_en_reg = - regulator_get(&pdev->dev, WLAN_EN_VREG_NAME); - if (IS_ERR(vreg_info->wlan_en_reg)) { - pr_err("%s:wlan_en vreg get failed\n", __func__); - ret = PTR_ERR(vreg_info->wlan_en_reg); - goto err_wlan_en_reg_get; - } + vreg_info->state = VREG_ON; + + if (!of_find_property((&pdev->dev)->of_node, gpio_info->name, NULL)) { + gpio_info->prop = false; + goto end; } - if (!penv->wlan_en_vreg_support) { - ret = cnss_get_wlan_enable_gpio(gpio_info, pdev); - if (ret) { - pr_err( - "%s:Failed to config the WLAN_EN gpio\n", __func__); - goto err_gpio_wlan_en; - } + gpio_info->prop = true; + ret = of_get_named_gpio((&pdev->dev)->of_node, + gpio_info->name, 0); + + if (ret >= 0) { + gpio_info->num = ret; + ret = 0; + } else { + if (ret == -EPROBE_DEFER) + pr_debug("get WLAN_EN GPIO probe defer\n"); + else + pr_err("can't get gpio %s ret %d", + gpio_info->name, ret); + goto err_get_gpio; } - vreg_info->state = VREG_ON; - ret = cnss_get_wlan_bootstrap_gpio(pdev); + ret = cnss_pinctrl_init(gpio_info, pdev); if (ret) { - pr_err("%s: Failed to enable wlan bootstrap gpio\n", __func__); - goto err_gpio_wlan_bootstrap; + pr_err("%s: pinctrl init failed!\n", __func__); + goto err_pinctrl_init; } + ret = cnss_wlan_gpio_init(gpio_info); + if (ret) { + pr_err("gpio init failed\n"); + goto err_gpio_init; + } + + if (of_find_property((&pdev->dev)->of_node, + WLAN_BOOTSTRAP_GPIO_NAME, NULL)) { + penv->wlan_bootstrap_gpio = + of_get_named_gpio((&pdev->dev)->of_node, + WLAN_BOOTSTRAP_GPIO_NAME, 0); + if (penv->wlan_bootstrap_gpio > 0) { + ret = cnss_wlan_bootstrap_gpio_init(); + if (ret) + goto err_gpio_init; + } else { + if (ret == -EPROBE_DEFER) { + pr_debug("%s: Get GPIO %s probe defer\n", + __func__, WLAN_BOOTSTRAP_GPIO_NAME); + } else { + pr_err("%s: Can't get GPIO %s, ret = %d", + __func__, WLAN_BOOTSTRAP_GPIO_NAME, + ret); + } + goto err_gpio_init; + } + } +end: return ret; -err_gpio_wlan_bootstrap: - cnss_put_wlan_enable_gpio(); -err_gpio_wlan_en: -err_wlan_en_reg_get: - vreg_info->wlan_en_reg = NULL; +err_gpio_init: +err_pinctrl_init: +err_get_gpio: if (vreg_info->soc_swreg) regulator_disable(vreg_info->soc_swreg); vreg_info->state = VREG_OFF; @@ -990,11 +929,7 @@ err_reg_sp2t_enable: err_reg_sp2t_set: if (vreg_info->wlan_reg_sp2t) regulator_put(vreg_info->wlan_reg_sp2t); - regulator_disable(vreg_info->wlan_reg); -err_reg_enable: - regulator_put(vreg_info->wlan_reg); -err_reg_get: cnss_disable_xtal_ldo(pdev); err_reg_xtal_enable: @@ -1005,6 +940,12 @@ err_reg_io_enable: err_reg_io_set: if (vreg_info->wlan_reg_io) regulator_put(vreg_info->wlan_reg_io); + regulator_disable(vreg_info->wlan_reg); + +err_reg_enable: + regulator_put(vreg_info->wlan_reg); + +err_reg_get: if (vreg_info->wlan_reg_core) regulator_disable(vreg_info->wlan_reg_core); @@ -1024,7 +965,7 @@ static void cnss_wlan_release_resources(void) if (penv->wlan_bootstrap_gpio > 0) gpio_free(penv->wlan_bootstrap_gpio); - cnss_put_wlan_enable_gpio(); + gpio_free(gpio_info->num); gpio_info->state = WLAN_EN_LOW; gpio_info->prop = false; cnss_wlan_vreg_set(vreg_info, VREG_OFF); @@ -1034,13 +975,13 @@ static void cnss_wlan_release_resources(void) regulator_put(vreg_info->ant_switch); if (vreg_info->wlan_reg_sp2t) regulator_put(vreg_info->wlan_reg_sp2t); - regulator_put(vreg_info->wlan_reg); if (vreg_info->wlan_reg_xtal) regulator_put(vreg_info->wlan_reg_xtal); if (vreg_info->wlan_reg_xtal_aon) regulator_put(vreg_info->wlan_reg_xtal_aon); if (vreg_info->wlan_reg_io) regulator_put(vreg_info->wlan_reg_io); + regulator_put(vreg_info->wlan_reg); if (vreg_info->wlan_reg_core) regulator_put(vreg_info->wlan_reg_core); vreg_info->state = VREG_OFF; @@ -1433,6 +1374,15 @@ int cnss_get_fw_image(struct image_desc_info *image_desc_info) !penv->fw_seg_count || !penv->bdata_seg_count) return -EINVAL; + /* Check for firmware setup trigger by usersapce is in progress + * and wait for complition of firmware setup. + */ + + if (atomic_read(&penv->fw_store_in_progress)) { + wait_for_completion_timeout(&penv->fw_setup_complete, + msecs_to_jiffies(FW_SETUP_DELAY)); + } + mutex_lock(&penv->fw_setup_stat_lock); image_desc_info->fw_addr = penv->fw_dma; image_desc_info->fw_size = penv->fw_dma_size; @@ -1610,6 +1560,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, { int ret = 0; struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; + struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; void *cpu_addr; dma_addr_t dma_handle; struct codeswap_codeseg_info *cnss_seg_info = NULL; @@ -1668,7 +1619,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, penv->pcie_link_state = PCIE_LINK_DOWN; } - cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (ret) { @@ -1676,9 +1627,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, goto err_pcie_suspend; } - mutex_lock(&penv->fw_setup_stat_lock); cnss_wlan_fw_mem_alloc(pdev); - mutex_unlock(&penv->fw_setup_stat_lock); ret = device_create_file(&penv->pldev->dev, &dev_attr_wlan_setup); @@ -1925,11 +1874,17 @@ static ssize_t fw_image_setup_store(struct device *dev, if (!penv) return -ENODEV; - mutex_lock(&penv->fw_setup_stat_lock); - pr_info("%s: Firmware setup in progress\n", __func__); + if (atomic_read(&penv->fw_store_in_progress)) { + pr_info("%s: Firmware setup in progress\n", __func__); + return 0; + } + + atomic_set(&penv->fw_store_in_progress, 1); + init_completion(&penv->fw_setup_complete); if (kstrtoint(buf, 0, &val)) { - mutex_unlock(&penv->fw_setup_stat_lock); + atomic_set(&penv->fw_store_in_progress, 0); + complete(&penv->fw_setup_complete); return -EINVAL; } @@ -1940,7 +1895,8 @@ static ssize_t fw_image_setup_store(struct device *dev, if (ret != 0) { pr_err("%s: Invalid parsing of FW image files %d", __func__, ret); - mutex_unlock(&penv->fw_setup_stat_lock); + atomic_set(&penv->fw_store_in_progress, 0); + complete(&penv->fw_setup_complete); return -EINVAL; } penv->fw_image_setup = val; @@ -1950,8 +1906,9 @@ static ssize_t fw_image_setup_store(struct device *dev, penv->bmi_test = val; } - pr_info("%s: Firmware setup completed\n", __func__); - mutex_unlock(&penv->fw_setup_stat_lock); + atomic_set(&penv->fw_store_in_progress, 0); + complete(&penv->fw_setup_complete); + return count; } @@ -2050,21 +2007,16 @@ int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg) { struct codeswap_codeseg_info *cnss_seg_info = penv->cnss_seg_info; - mutex_lock(&penv->fw_setup_stat_lock); if (!cnss_seg_info) { swap_seg = NULL; - mutex_unlock(&penv->fw_setup_stat_lock); return -ENOENT; } - if (!atomic_read(&penv->fw_available)) { pr_debug("%s: fw is not available\n", __func__); - mutex_unlock(&penv->fw_setup_stat_lock); return -ENOENT; } *swap_seg = *cnss_seg_info; - mutex_unlock(&penv->fw_setup_stat_lock); return 0; } @@ -2083,6 +2035,15 @@ static void cnss_wlan_memory_expansion(void) u_int32_t total_length = 0; struct pci_dev *pdev; + /* Check for firmware setup trigger by usersapce is in progress + * and wait for complition of firmware setup. + */ + + if (atomic_read(&penv->fw_store_in_progress)) { + wait_for_completion_timeout(&penv->fw_setup_complete, + msecs_to_jiffies(FW_SETUP_DELAY)); + } + mutex_lock(&penv->fw_setup_stat_lock); filename = cnss_wlan_get_evicted_data_file(); pdev = penv->pdev; @@ -2315,7 +2276,8 @@ again: msleep(WLAN_BOOTSTRAP_DELAY); } - cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_HIGH); + msleep(WLAN_ENABLE_DELAY); if (!pdev) { pr_debug("%s: invalid pdev. register pci device\n", __func__); @@ -2398,7 +2360,8 @@ again: cnss_get_pci_dev_bus_number(pdev), pdev, PM_OPTIONS); penv->pcie_link_state = PCIE_LINK_DOWN; - cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); + msleep(WLAN_ENABLE_DELAY); cnss_wlan_vreg_set(vreg_info, VREG_OFF); msleep(POWER_ON_DELAY); probe_again++; @@ -2425,7 +2388,7 @@ err_pcie_link_up: } err_pcie_reg: - cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (penv->pdev) { pr_err("%d: Unregistering PCI device\n", __LINE__); @@ -2506,7 +2469,8 @@ void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver) cut_power: penv->driver = NULL; - cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); + if (cnss_wlan_vreg_set(vreg_info, VREG_OFF)) pr_err("wlan vreg OFF failed\n"); } @@ -2618,7 +2582,8 @@ static int cnss_shutdown(const struct subsys_desc *subsys, bool force_stop) } cut_power: - cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); + if (cnss_wlan_vreg_set(vreg_info, VREG_OFF)) pr_err("cnss: Failed to set WLAN VREG_OFF!\n"); @@ -2651,7 +2616,8 @@ static int cnss_powerup(const struct subsys_desc *subsys) } msleep(POWER_ON_DELAY); - cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_HIGH); + msleep(WLAN_ENABLE_DELAY); if (!pdev) { pr_err("%d: invalid pdev\n", __LINE__); @@ -2711,7 +2677,7 @@ err_wlan_reinit: penv->pcie_link_state = PCIE_LINK_DOWN; err_pcie_link_up: - cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (penv->pdev) { pr_err("%d: Unregistering pci device\n", __LINE__); @@ -2893,17 +2859,13 @@ static int cnss_probe(struct platform_device *pdev) penv->vreg_info.wlan_reg = NULL; penv->vreg_info.state = VREG_OFF; penv->pci_register_again = false; - mutex_init(&penv->fw_setup_stat_lock); ret = cnss_wlan_get_resources(pdev); if (ret) goto err_get_wlan_res; - ret = cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); - if (ret) { - pr_err("%s: Failed to enable WLAN enable gpio\n", __func__); - goto err_get_rc; - } + cnss_wlan_gpio_set(&penv->gpio_info, WLAN_EN_HIGH); + msleep(WLAN_ENABLE_DELAY); ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num); if (ret) { @@ -3054,6 +3016,8 @@ skip_ramdump: memset(phys_to_virt(0), 0, SZ_4K); #endif + atomic_set(&penv->fw_store_in_progress, 0); + mutex_init(&penv->fw_setup_stat_lock); ret = device_create_file(dev, &dev_attr_fw_image_setup); if (ret) { pr_err("cnss: fw_image_setup sys file creation failed\n"); @@ -3098,7 +3062,7 @@ err_subsys_reg: err_esoc_reg: err_pcie_enumerate: err_get_rc: - cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_gpio_set(&penv->gpio_info, WLAN_EN_LOW); cnss_wlan_release_resources(); err_get_wlan_res: @@ -3109,6 +3073,8 @@ err_get_wlan_res: static int cnss_remove(struct platform_device *pdev) { + struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; + unregister_pm_notifier(&cnss_pm_notifier); device_remove_file(&pdev->dev, &dev_attr_fw_image_setup); @@ -3129,7 +3095,7 @@ static int cnss_remove(struct platform_device *pdev) } } - cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); if (penv->wlan_bootstrap_gpio > 0) gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW); cnss_wlan_release_resources(); @@ -3630,7 +3596,8 @@ static int __cnss_pcie_power_up(struct device *dev) msleep(WLAN_BOOTSTRAP_DELAY); } - cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_HIGH); + msleep(WLAN_ENABLE_DELAY); return 0; } @@ -3643,7 +3610,8 @@ static int __cnss_pcie_power_down(struct device *dev) vreg_info = &penv->vreg_info; gpio_info = &penv->gpio_info; - cnss_configure_wlan_en_gpio(WLAN_EN_LOW); + cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); + if (penv->wlan_bootstrap_gpio > 0) gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 019d7165a045f721819d281d227a656eb5c88335..d59769e858f4c6ff4778dc1e80f738ba69d9d6df 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2539,7 +2539,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, tasklet_hrtimer_init(&data->beacon_timer, mac80211_hwsim_beacon, - CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); spin_lock_bh(&hwsim_radio_lock); list_add_tail(&data->list, &hwsim_radios); diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c index d0a74744f70acac2b54446aa99b645ee14beb0b3..82b90ad00f8b373b769b628f12bea9fd0750db13 100644 --- a/drivers/net/wireless/wcnss/wcnss_vreg.c +++ b/drivers/net/wireless/wcnss/wcnss_vreg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -417,18 +417,13 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size, if (regulators[i].state == VREG_NULL_CONFIG) continue; - if (cfg->wcn_external_gpio_support) { - if (!memcmp(regulators[i].name, VDD_PA, sizeof(VDD_PA))) - continue; - } - /* Remove PWM mode */ if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) { - rc = regulator_set_load(regulators[i].regulator, 0); - if (rc < 0) { - pr_err("regulator set load(%s) failed (%d)\n", - regulators[i].name, rc); - } + rc = regulator_set_optimum_mode( + regulators[i].regulator, 0); + if (rc < 0) + pr_err("regulator_set_optimum_mode(%s) failed (%d)\n", + regulators[i].name, rc); } /* Set voltage to lowest level */ @@ -483,12 +478,7 @@ static int wcnss_vregs_on(struct device *dev, } for (i = 0; i < size; i++) { - if (cfg->wcn_external_gpio_support) { - if (!memcmp(regulators[i].name, VDD_PA, sizeof(VDD_PA))) - continue; - } - - /* Get regulator source */ + /* Get regulator source */ regulators[i].regulator = regulator_get(dev, regulators[i].name); if (IS_ERR(regulators[i].regulator)) { @@ -528,11 +518,11 @@ static int wcnss_vregs_on(struct device *dev, /* Vote for PWM/PFM mode if needed */ if (voltage_level[i].uA_load && (reg_cnt > 0)) { - rc = regulator_set_load(regulators[i].regulator, - voltage_level[i].uA_load); + rc = regulator_set_optimum_mode(regulators[i].regulator, + voltage_level[i].uA_load); if (rc < 0) { - pr_err("regulator set load(%s) failed (%d)\n", - regulators[i].name, rc); + pr_err("regulator_set_optimum_mode(%s) failed (%d)\n", + regulators[i].name, rc); goto fail; } regulators[i].state |= VREG_OPTIMUM_MODE_MASK; diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index e99d46ca51b04df6310b52ebb6c736407f688806..505a9e01677796dd9eccc357eab9827e13b11f9c 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include @@ -57,7 +56,6 @@ #define WCNSS_PM_QOS_TIMEOUT 15000 #define IS_CAL_DATA_PRESENT 0 #define WAIT_FOR_CBC_IND 2 -#define WCNSS_DUAL_BAND_CAPABILITY_OFFSET BIT(8) /* module params */ #define WCNSS_CONFIG_UNSPECIFIED (-1) @@ -121,8 +119,6 @@ static DEFINE_SPINLOCK(reg_spinlock); #define PRONTO_PMU_COM_CSR_OFFSET 0x1040 #define PRONTO_PMU_SOFT_RESET_OFFSET 0x104C -#define PRONTO_QFUSE_DUAL_BAND_OFFSET 0x0018 - #define A2XB_CFG_OFFSET 0x00 #define A2XB_INT_SRC_OFFSET 0x0c #define A2XB_TSTBUS_CTRL_OFFSET 0x14 @@ -385,7 +381,6 @@ static struct { void __iomem *pronto_saw2_base; void __iomem *pronto_pll_base; void __iomem *pronto_mcu_base; - void __iomem *pronto_qfuse; void __iomem *wlan_tx_status; void __iomem *wlan_tx_phy_aborts; void __iomem *wlan_brdg_err_source; @@ -402,7 +397,7 @@ static struct { int user_cal_read; int user_cal_available; u32 user_cal_rcvd; - u32 user_cal_exp_size; + int user_cal_exp_size; int iris_xo_mode_set; int fw_vbatt_state; char wlan_nv_macAddr[WLAN_MAC_ADDR_SIZE]; @@ -428,9 +423,6 @@ static struct { int pc_disabled; struct delayed_work wcnss_pm_qos_del_req; struct mutex pm_qos_mutex; - struct clk *snoc_wcnss; - unsigned int snoc_wcnss_clock_freq; - bool is_dual_band_disabled; } *penv = NULL; static ssize_t wcnss_wlan_macaddr_store(struct device *dev, @@ -603,31 +595,7 @@ void wcnss_pronto_is_a2xb_bus_stall(void *tst_addr, u32 fifo_mask, char *type) } } -int wcnss_get_dual_band_capability_info(struct platform_device *pdev) -{ - u32 reg = 0; - struct resource *res; - - res = platform_get_resource_byname( - pdev, IORESOURCE_MEM, "pronto_qfuse"); - if (!res) - return -EINVAL; - - penv->pronto_qfuse = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(penv->pronto_qfuse)) - return -ENOMEM; - - reg = readl_relaxed(penv->pronto_qfuse + - PRONTO_QFUSE_DUAL_BAND_OFFSET); - if (reg & WCNSS_DUAL_BAND_CAPABILITY_OFFSET) - penv->is_dual_band_disabled = true; - else - penv->is_dual_band_disabled = false; - - return 0; -} - -/* Log pronto debug registers during SSR Timeout CB */ +/* Log pronto debug registers before sending reset interrupt */ void wcnss_pronto_log_debug_regs(void) { void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr; @@ -1715,14 +1683,6 @@ int wcnss_wlan_iris_xo_mode(void) } EXPORT_SYMBOL(wcnss_wlan_iris_xo_mode); -int wcnss_wlan_dual_band_disabled(void) -{ - if (penv && penv->pdev) - return penv->is_dual_band_disabled; - - return -EINVAL; -} -EXPORT_SYMBOL(wcnss_wlan_dual_band_disabled); void wcnss_suspend_notify(void) { @@ -2757,23 +2717,23 @@ wcnss_trigger_config(struct platform_device *pdev) int is_pronto_vadc; int is_pronto_v3; int pil_retry = 0; - struct wcnss_wlan_config *wlan_cfg = &penv->wlan_config; - struct device_node *node = (&pdev->dev)->of_node; - int has_pronto_hw = of_property_read_bool(node, "qcom,has-pronto-hw"); + int has_pronto_hw = of_property_read_bool(pdev->dev.of_node, + "qcom,has-pronto-hw"); + + is_pronto_vadc = of_property_read_bool(pdev->dev.of_node, + "qcom,is-pronto-vadc"); - is_pronto_vadc = of_property_read_bool(node, "qcom,is-pronto-vadc"); - is_pronto_v3 = of_property_read_bool(node, "qcom,is-pronto-v3"); + is_pronto_v3 = of_property_read_bool(pdev->dev.of_node, + "qcom,is-pronto-v3"); - penv->is_vsys_adc_channel = - of_property_read_bool(node, "qcom,has-vsys-adc-channel"); - penv->is_a2xb_split_reg = - of_property_read_bool(node, "qcom,has-a2xb-split-reg"); + penv->is_vsys_adc_channel = of_property_read_bool(pdev->dev.of_node, + "qcom,has-vsys-adc-channel"); - wlan_cfg->wcn_external_gpio_support = - of_property_read_bool(node, "qcom,wcn-external-gpio-support"); + penv->is_a2xb_split_reg = of_property_read_bool(pdev->dev.of_node, + "qcom,has-a2xb-split-reg"); - if (of_property_read_u32(node, "qcom,wlan-rx-buff-count", - &penv->wlan_rx_buff_count)) { + if (of_property_read_u32(pdev->dev.of_node, + "qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) { penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT; } @@ -2834,18 +2794,15 @@ wcnss_trigger_config(struct platform_device *pdev) goto fail; } - if (!wlan_cfg->wcn_external_gpio_support) { - index++; - ret = wcnss_dt_parse_vreg_level( - &pdev->dev, index, - "qcom,iris-vddpa-current", - "qcom,iris-vddpa-voltage-level", - penv->wlan_config.iris_vlevel); - if (ret) { - dev_err(&pdev->dev, - "error reading voltage-level property\n"); - goto fail; - } + index++; + ret = wcnss_dt_parse_vreg_level(&pdev->dev, index, + "qcom,iris-vddpa-current", + "qcom,iris-vddpa-voltage-level", + penv->wlan_config.iris_vlevel); + + if (ret) { + dev_err(&pdev->dev, "error reading voltage-level property\n"); + goto fail; } index++; @@ -2868,8 +2825,8 @@ wcnss_trigger_config(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) { if (has_pronto_hw) { - has_48mhz_xo = - of_property_read_bool(node, "qcom,has-48mhz-xo"); + has_48mhz_xo = of_property_read_bool(pdev->dev.of_node, + "qcom,has-48mhz-xo"); } else { has_48mhz_xo = pdata->has_48mhz_xo; } @@ -2880,8 +2837,8 @@ wcnss_trigger_config(struct platform_device *pdev) penv->wlan_config.is_pronto_v3 = is_pronto_v3; if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) { - has_autodetect_xo = - of_property_read_bool(node, "qcom,has-autodetect-xo"); + has_autodetect_xo = of_property_read_bool(pdev->dev.of_node, + "qcom,has-autodetect-xo"); } penv->thermal_mitigation = 0; @@ -3161,16 +3118,6 @@ wcnss_trigger_config(struct platform_device *pdev) __func__); goto fail_ioremap2; } - - if (of_property_read_bool(node, - "qcom,is-dual-band-disabled")) { - ret = wcnss_get_dual_band_capability_info(pdev); - if (ret) { - pr_err( - "%s: failed to get dual band info\n", __func__); - goto fail_ioremap2; - } - } } penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss"); @@ -3182,21 +3129,6 @@ wcnss_trigger_config(struct platform_device *pdev) penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED; } - penv->snoc_wcnss = devm_clk_get(&penv->pdev->dev, "snoc_wcnss"); - if (IS_ERR(penv->snoc_wcnss)) { - pr_err("%s: couldn't get snoc_wcnss\n", __func__); - penv->snoc_wcnss = NULL; - } else { - if (of_property_read_u32(pdev->dev.of_node, - "qcom,snoc-wcnss-clock-freq", - &penv->snoc_wcnss_clock_freq)) { - pr_debug("%s: wcnss snoc clock frequency is not defined\n", - __func__); - devm_clk_put(&penv->pdev->dev, penv->snoc_wcnss); - penv->snoc_wcnss = NULL; - } - } - if (penv->wlan_config.is_pronto_vadc) { penv->vadc_dev = qpnp_get_vadc(&penv->pdev->dev, "wcnss"); @@ -3259,38 +3191,6 @@ fail: return ret; } -/* Driver requires to directly vote the snoc clocks - * To enable and disable snoc clock, it call - * wcnss_snoc_vote function - */ -void wcnss_snoc_vote(bool clk_chk_en) -{ - int rc; - - if (!penv->snoc_wcnss) { - pr_err("%s: couldn't get clk snoc_wcnss\n", __func__); - return; - } - - if (clk_chk_en) { - rc = clk_set_rate(penv->snoc_wcnss, - penv->snoc_wcnss_clock_freq); - if (rc) { - pr_err("%s: snoc_wcnss_clk-clk_set_rate failed =%d\n", - __func__, rc); - return; - } - - if (clk_prepare_enable(penv->snoc_wcnss)) { - pr_err("%s: snoc_wcnss clk enable failed\n", __func__); - return; - } - } else { - clk_disable_unprepare(penv->snoc_wcnss); - } -} -EXPORT_SYMBOL(wcnss_snoc_vote); - /* wlan prop driver cannot invoke cancel_work_sync * function directly, so to invoke this function it * call wcnss_flush_work function diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 34a062ccb11d85ac6d7c4a1eb33f6e0282367389..888e9cfef51ae8702872f637129562723aafe1eb 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -321,7 +321,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) queue->rx.req_prod_pvt = req_prod; /* Not enough requests? Try again later. */ - if (req_prod - queue->rx.sring->req_prod < NET_RX_SLOTS_MIN) { + if (req_prod - queue->rx.rsp_cons < NET_RX_SLOTS_MIN) { mod_timer(&queue->rx_refill_timer, jiffies + (HZ/10)); return; } diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index b8a5a8e8f57d13680291637be1328ad132d96f76..044253dca30a433549a37ec7e28c3a6c161d38a5 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -27,13 +27,6 @@ enum { NVME_NS_LIGHTNVM = 1, }; -/* The below value is the specific amount of delay needed before checking - * readiness in case of the PCI_DEVICE(0x1c58, 0x0003), which needs the - * NVME_QUIRK_DELAY_BEFORE_CHK_RDY quirk enabled. The value (in ms) was - * found empirically. - */ -#define NVME_QUIRK_DELAY_AMOUNT 2000 - /* * Represents an NVM Express device. Each nvme_dev is a PCI function. */ diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 4c673d45f1bd7895fa1b4a84c9b8a5d01c17da37..c851bc53831c1267c0cccab074e5cd141b1d5825 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1633,15 +1633,10 @@ static int nvme_wait_ready(struct nvme_dev *dev, u64 cap, bool enabled) */ static int nvme_disable_ctrl(struct nvme_dev *dev, u64 cap) { - struct pci_dev *pdev = to_pci_dev(dev->dev); - dev->ctrl_config &= ~NVME_CC_SHN_MASK; dev->ctrl_config &= ~NVME_CC_ENABLE; writel(dev->ctrl_config, &dev->bar->cc); - if (pdev->vendor == 0x1c58 && pdev->device == 0x0003) - msleep(NVME_QUIRK_DELAY_AMOUNT); - return nvme_wait_ready(dev, cap, false); } diff --git a/drivers/of/base.c b/drivers/of/base.c index 31341290cd9136ab0b2830c67422eb334ed32f4e..064299a672afde803c6af1b6c95a04b1aa63aa6f 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -17,6 +17,11 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index ca175710c4c81cf1905bd671c604f950342487e3..0438512f4d69be3f857fdd0e923859c0c18bfe5d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -632,12 +632,9 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, const char *pathp; int offset, rc = 0, depth = -1; - if (!blob) - return 0; - - for (offset = fdt_next_node(blob, -1, &depth); - offset >= 0 && depth >= 0 && !rc; - offset = fdt_next_node(blob, offset, &depth)) { + for (offset = fdt_next_node(blob, -1, &depth); + offset >= 0 && depth >= 0 && !rc; + offset = fdt_next_node(blob, offset, &depth)) { pathp = fdt_get_name(blob, offset, NULL); if (*pathp == '/') diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index e16ea5717b7f76df9c4734ee0f9373fb8e758b45..8845d97fc41b2738052c06ec0c2347a5562e2ed6 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1,6 +1,11 @@ /* * Self tests for device tree subsystem */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "### dt-test ### " fmt diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 34f1d6b41fb9069f826d8bfad35cf69cf15a88ac..8e11fb2831cd20cb9e4b95415aee05041bb7813b 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -741,8 +741,6 @@ ccio_map_single(struct device *dev, void *addr, size_t size, BUG_ON(!dev); ioc = GET_IOC(dev); - if (!ioc) - return DMA_ERROR_CODE; BUG_ON(size <= 0); @@ -807,10 +805,6 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size, BUG_ON(!dev); ioc = GET_IOC(dev); - if (!ioc) { - WARN_ON(!ioc); - return; - } DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long)iova, size); @@ -914,8 +908,6 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents, BUG_ON(!dev); ioc = GET_IOC(dev); - if (!ioc) - return 0; DBG_RUN_SG("%s() START %d entries\n", __func__, nents); @@ -988,10 +980,6 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, BUG_ON(!dev); ioc = GET_IOC(dev); - if (!ioc) { - WARN_ON(!ioc); - return; - } DBG_RUN_SG("%s() START %d entries, %p,%x\n", __func__, nents, sg_virt(sglist), sglist->length); diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 7b0ca1551d7bcad108c57a42d80368bcbf239044..a0580afe1713a5f58db5e96da635028856200a08 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -154,10 +154,7 @@ struct dino_device }; /* Looks nice and keeps the compiler happy */ -#define DINO_DEV(d) ({ \ - void *__pdata = d; \ - BUG_ON(!__pdata); \ - (struct dino_device *)__pdata; }) +#define DINO_DEV(d) ((struct dino_device *) d) /* diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index d0c2759076a2b122648ebad5f0164c685880b540..42844c2bc065bcd8bc486a11ae9714e9d31adc20 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -111,10 +111,8 @@ static u32 lba_t32; /* Looks nice and keeps the compiler happy */ -#define LBA_DEV(d) ({ \ - void *__pdata = d; \ - BUG_ON(!__pdata); \ - (struct lba_device *)__pdata; }) +#define LBA_DEV(d) ((struct lba_device *) (d)) + /* ** Only allow 8 subsidiary busses per LBA diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index d6326144ce01e1d1eed7c399914f1005f6624faf..225049b492e535f7bf30ac8ef00f110d4647c0c2 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -691,8 +691,6 @@ static int sba_dma_supported( struct device *dev, u64 mask) return 0; ioc = GET_IOC(dev); - if (!ioc) - return 0; /* * check if mask is >= than the current max IO Virt Address @@ -724,8 +722,6 @@ sba_map_single(struct device *dev, void *addr, size_t size, int pide; ioc = GET_IOC(dev); - if (!ioc) - return DMA_ERROR_CODE; /* save offset bits */ offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK; @@ -807,10 +803,6 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long) iova, size); ioc = GET_IOC(dev); - if (!ioc) { - WARN_ON(!ioc); - return; - } offset = iova & ~IOVP_MASK; iova ^= offset; /* clear offset bits */ size += offset; @@ -950,8 +942,6 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, DBG_RUN_SG("%s() START %d entries\n", __func__, nents); ioc = GET_IOC(dev); - if (!ioc) - return 0; /* Fast path single entry scatterlists. */ if (nents == 1) { @@ -1037,10 +1027,6 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, __func__, nents, sg_virt(sglist), sglist->length); ioc = GET_IOC(dev); - if (!ioc) { - WARN_ON(!ioc); - return; - } #ifdef SBA_COLLECT_STATS ioc->usg_calls++; diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index a741c9c7d115d3e1281b144dfba28e30dfe4d645..217c7ce3f57bec2515adec88d4e250bbc3eb6215 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -278,7 +278,6 @@ #define PERST_PROPAGATION_DELAY_US_MIN 1000 #define PERST_PROPAGATION_DELAY_US_MAX 1005 -#define SWITCH_DELAY_MAX 20 #define REFCLK_STABILIZATION_DELAY_US_MIN 1000 #define REFCLK_STABILIZATION_DELAY_US_MAX 1005 #define LINK_UP_TIMEOUT_US_MIN 5000 @@ -596,6 +595,7 @@ struct msm_pcie_dev_t { bool cfg_access; spinlock_t cfg_lock; unsigned long irqsave_flags; + struct mutex enumerate_lock; struct mutex setup_lock; struct irq_domain *irq_domain; @@ -626,7 +626,6 @@ struct msm_pcie_dev_t { bool ext_ref_clk; bool common_phy; uint32_t ep_latency; - uint32_t switch_latency; uint32_t wr_halt_size; uint32_t cpl_timeout; uint32_t current_bdf; @@ -703,9 +702,6 @@ static u32 num_rc_on; /* global lock for PCIe common PHY */ static struct mutex com_phy_lock; -/* global lock for PCIe enumeration */ -static struct mutex enumerate_lock; - /* Table to track info of PCIe devices */ static struct msm_pcie_device_info msm_pcie_dev_tbl[MAX_RC_NUM * MAX_DEVICE_NUM]; @@ -1739,8 +1735,7 @@ static bool pcie_phy_is_ready(struct msm_pcie_dev_t *dev) static int msm_pcie_restore_sec_config(struct msm_pcie_dev_t *dev) { - int ret; - u64 scm_ret; + int ret, scm_ret; if (!dev) { pr_err("PCIe: the input pcie dev is NULL.\n"); @@ -1750,7 +1745,7 @@ static int msm_pcie_restore_sec_config(struct msm_pcie_dev_t *dev) ret = scm_restore_sec_cfg(dev->scm_dev_id, 0, &scm_ret); if (ret || scm_ret) { PCIE_ERR(dev, - "PCIe: RC%d failed(%d) to restore sec config, scm_ret=%llu\n", + "PCIe: RC%d failed(%d) to restore sec config, scm_ret=%d\n", dev->rc_idx, ret, scm_ret); return ret ? ret : -EINVAL; } @@ -1989,8 +1984,6 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->common_phy); PCIE_DBG_FS(dev, "ep_latency: %dms\n", dev->ep_latency); - PCIE_DBG_FS(dev, "switch_latency: %dms\n", - dev->switch_latency); PCIE_DBG_FS(dev, "wr_halt_size: 0x%x\n", dev->wr_halt_size); PCIE_DBG_FS(dev, "cpl_timeout: 0x%x\n", @@ -4682,15 +4675,7 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) goto link_fail; } - if (dev->switch_latency) { - PCIE_DBG(dev, "switch_latency: %dms\n", - dev->switch_latency); - if (dev->switch_latency <= SWITCH_DELAY_MAX) - usleep_range(dev->switch_latency * 1000, - dev->switch_latency * 1000); - else - msleep(dev->switch_latency); - } + msleep(500); msm_pcie_config_controller(dev); @@ -5052,7 +5037,7 @@ int msm_pcie_enumerate(u32 rc_idx) int ret = 0, bus_ret = 0, scan_ret = 0; struct msm_pcie_dev_t *dev = &msm_pcie_dev[rc_idx]; - mutex_lock(&enumerate_lock); + mutex_lock(&dev->enumerate_lock); PCIE_DBG(dev, "Enumerate RC%d\n", rc_idx); @@ -5171,7 +5156,7 @@ int msm_pcie_enumerate(u32 rc_idx) } out: - mutex_unlock(&enumerate_lock); + mutex_unlock(&dev->enumerate_lock); return ret; } @@ -6294,20 +6279,6 @@ static int msm_pcie_probe(struct platform_device *pdev) PCIE_DBG(&msm_pcie_dev[rc_idx], "RC%d: ep-latency: 0x%x.\n", rc_idx, msm_pcie_dev[rc_idx].ep_latency); - msm_pcie_dev[rc_idx].switch_latency = 0; - ret = of_property_read_u32((&pdev->dev)->of_node, - "qcom,switch-latency", - &msm_pcie_dev[rc_idx].switch_latency); - - if (ret) - PCIE_DBG(&msm_pcie_dev[rc_idx], - "RC%d: switch-latency does not exist.\n", - rc_idx); - else - PCIE_DBG(&msm_pcie_dev[rc_idx], - "RC%d: switch-latency: 0x%x.\n", - rc_idx, msm_pcie_dev[rc_idx].switch_latency); - msm_pcie_dev[rc_idx].wr_halt_size = 0; ret = of_property_read_u32(pdev->dev.of_node, "qcom,wr-halt-size", @@ -6633,7 +6604,6 @@ int __init pcie_init(void) pcie_drv.rc_num = 0; mutex_init(&pcie_drv.drv_lock); mutex_init(&com_phy_lock); - mutex_init(&enumerate_lock); for (i = 0; i < MAX_RC_NUM; i++) { snprintf(rc_name, MAX_RC_NAME_LEN, "pcie%d-short", i); @@ -6668,6 +6638,7 @@ int __init pcie_init(void) rc_name, i); spin_lock_init(&msm_pcie_dev[i].cfg_lock); msm_pcie_dev[i].cfg_access = true; + mutex_init(&msm_pcie_dev[i].enumerate_lock); mutex_init(&msm_pcie_dev[i].setup_lock); mutex_init(&msm_pcie_dev[i].recovery_lock); spin_lock_init(&msm_pcie_dev[i].linkdown_lock); diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 39400dda27c27909a30adb8224450b6b544c4ab5..63ec68e6ac2ae6025888fbf969b138259a251d2f 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -552,7 +552,6 @@ static void armpmu_init(struct arm_pmu *armpmu) .stop = armpmu_stop, .read = armpmu_read, .filter_match = armpmu_filter_match, - .events_across_hotplug = 1, }; } diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 312c78b27a3206c813c85912e14b570ffa43a0a6..903384ec978b08b53903e0711c5691f22d26e87a 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -271,4 +271,10 @@ config PINCTRL_TB10X depends on OF && ARC_PLAT_TB10X select GPIOLIB +config PINCTRL_SOMC + bool "SoMC pinctrl driver" + default n + help + Select this to enable SoMC pinctrl driver. + endmenu diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c index 5da9c95dccb7ee8834ad768b3b9a0449c08a9142..6bbda6b4ab50d9e930544e4bfd72a67904261f85 100644 --- a/drivers/pinctrl/freescale/pinctrl-mxs.c +++ b/drivers/pinctrl/freescale/pinctrl-mxs.c @@ -195,16 +195,6 @@ static int mxs_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, return 0; } -static void mxs_pinctrl_rmwl(u32 value, u32 mask, u8 shift, void __iomem *reg) -{ - u32 tmp; - - tmp = readl(reg); - tmp &= ~(mask << shift); - tmp |= value << shift; - writel(tmp, reg); -} - static int mxs_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { @@ -222,7 +212,8 @@ static int mxs_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned selector, reg += bank * 0x20 + pin / 16 * 0x10; shift = pin % 16 * 2; - mxs_pinctrl_rmwl(g->muxsel[i], 0x3, shift, reg); + writel(0x3 << shift, reg + CLR); + writel(g->muxsel[i] << shift, reg + SET); } return 0; @@ -289,7 +280,8 @@ static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev, /* mA */ if (config & MA_PRESENT) { shift = pin % 8 * 4; - mxs_pinctrl_rmwl(ma, 0x3, shift, reg); + writel(0x3 << shift, reg + CLR); + writel(ma << shift, reg + SET); } /* vol */ diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c index b505b87661f86fb48f6598f398344db444076fbc..9677807db364d70ee4512799e26449bccba56a08 100644 --- a/drivers/pinctrl/meson/pinctrl-meson8b.c +++ b/drivers/pinctrl/meson/pinctrl-meson8b.c @@ -732,8 +732,8 @@ static const char * const sdxc_c_groups[] = { static const char * const nand_groups[] = { "nand_io", "nand_io_ce0", "nand_io_ce1", "nand_io_rb0", "nand_ale", "nand_cle", - "nand_wen_clk", "nand_ren_clk", "nand_dqs_0", - "nand_dqs_1" + "nand_wen_clk", "nand_ren_clk", "nand_dqs0", + "nand_dqs1" }; static const char * const nor_groups[] = { diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 502b91f455d7b8656fa4e2146da94c6ab939e70b..31892072d0b03f44bf84a846c9683d458c003c94 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_PINCTRL_MSM8998) += pinctrl-msm8998.o obj-$(CONFIG_PINCTRL_SDM660) += pinctrl-sdm660.o obj-$(CONFIG_PINCTRL_WCD) += pinctrl-wcd.o obj-$(CONFIG_PINCTRL_LPI) += pinctrl-lpi.o +obj-$(CONFIG_PINCTRL_SOMC) += pinctrl-somc.o diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c index bcb29c02f4b019288f7bc94b15775467941d9fb4..117190f01b9f44d0183bcdbd038d9be2f504451c 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c @@ -11,6 +11,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index c5a351e7bb4e646321dbb111bfa95a753aa32854..adb38a30ebe26806cee75e53733e5a1c50d86a97 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -66,6 +66,7 @@ struct msm_pinctrl { DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); + DECLARE_BITMAP(disabled_pins, MAX_NR_GPIO); const struct msm_pinctrl_soc_data *soc; void __iomem *regs; @@ -502,9 +503,14 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) { unsigned gpio = chip->base; unsigned i; + struct msm_pinctrl *pctrl = container_of(chip, + struct msm_pinctrl, chip); for (i = 0; i < chip->ngpio; i++, gpio++) { - msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); + if (test_bit(i, pctrl->disabled_pins)) + seq_printf(s, " gpio%d is not accessible.", i); + else + msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); seq_puts(s, "\n"); } } @@ -947,6 +953,8 @@ int msm_pinctrl_probe(struct platform_device *pdev, struct msm_pinctrl *pctrl; struct resource *res; int ret; + int disabled_pins_num; + const struct device_node *np = pdev->dev.of_node; msm_pinctrl_data = pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); @@ -982,6 +990,23 @@ int msm_pinctrl_probe(struct platform_device *pdev, return PTR_ERR(pctrl->pctrl); } + disabled_pins_num = of_property_count_u32_elems(np, "disabled-pins"); + if (disabled_pins_num > 0) { + int i; + u32 pin; + + for (i = 0; i < disabled_pins_num; i++) { + of_property_read_u32_index(np, + "disabled-pins", i, &pin); + if (pin < MAX_NR_GPIO) { + set_bit(pin, pctrl->disabled_pins); + dev_info(&pdev->dev, "pin %d disabled\n", pin); + } else { + dev_err(&pdev->dev, "pin %d out of range\n", + pin); + } + } + } ret = msm_gpio_init(pctrl); if (ret) { pinctrl_unregister(pctrl->pctrl); diff --git a/drivers/pinctrl/qcom/pinctrl-somc.c b/drivers/pinctrl/qcom/pinctrl-somc.c new file mode 100644 index 0000000000000000000000000000000000000000..4b7d3769d4e9365f5601fad7df6d9a36e1d91bd6 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-somc.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#define PLATFORM_COMMON_DEFAULT "platform_common_default" +#define PRODUCT_COMMON_DEFAULT "product_common_default" +#define VARIANT_DEFAULT "variant_default" + +static int somc_pinctrl_probe(struct platform_device *pdev) +{ + struct pinctrl *pin; + struct pinctrl_state *plat_default, *prod_default, *variant_default; + int ret = 0; + + pin = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(pin)) { + dev_err(&pdev->dev, "faild to get pinctrl handle\n"); + ret = -EPROBE_DEFER; + goto out; + }; + + /* Platform common settings */ + plat_default = pinctrl_lookup_state(pin, PLATFORM_COMMON_DEFAULT); + if (IS_ERR(plat_default)) { + dev_dbg(&pdev->dev, + "Can not lookup %s state\n", PLATFORM_COMMON_DEFAULT); + } else { + ret = pinctrl_select_state(pin, plat_default); + if (ret) + dev_err(&pdev->dev, + "failed to select %s state\n", + PLATFORM_COMMON_DEFAULT); + } + + /* Product common settings */ + prod_default = pinctrl_lookup_state(pin, PRODUCT_COMMON_DEFAULT); + if (IS_ERR(prod_default)) { + dev_dbg(&pdev->dev, + "Can not lookup %s state\n", PRODUCT_COMMON_DEFAULT); + } else { + ret = pinctrl_select_state(pin, prod_default); + if (ret) + dev_err(&pdev->dev, + "failed to select %s state\n", + PRODUCT_COMMON_DEFAULT); + } + + /* Variant specific settings */ + variant_default = pinctrl_lookup_state(pin, VARIANT_DEFAULT); + if (IS_ERR(variant_default)) { + dev_dbg(&pdev->dev, + "Can not lookup %s state\n", VARIANT_DEFAULT); + } else { + ret = pinctrl_select_state(pin, variant_default); + if (ret) + dev_err(&pdev->dev, + "failed to select %s state\n", + VARIANT_DEFAULT); + } + + devm_pinctrl_put(pin); +out: + return ret; +}; + +static const struct of_device_id somc_pinctrl_dt_match[] = { + { .compatible = "somc-pinctrl", }, + { }, +}; + +static struct platform_driver somc_pinctrl_drv = { + .probe = somc_pinctrl_probe, + .driver = { + .name = "somc-pinctrl", + .owner = THIS_MODULE, + .of_match_table = somc_pinctrl_dt_match, + }, +}; + +static int __init somc_pinctrl_drv_register(void) +{ + return platform_driver_register(&somc_pinctrl_drv); +} +arch_initcall(somc_pinctrl_drv_register); + +static void __exit somc_pinctrl_drv_unregister(void) +{ + platform_driver_unregister(&somc_pinctrl_drv); +} +module_exit(somc_pinctrl_drv_unregister); + +MODULE_LICENSE("GPL v2"); + + diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 73547abc5cf56fbddf49a8bdca945a39dc9d9638..4c0f13dfd0b99ad526e75dc219857095e7c98126 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 699efb1a8c45c041e291fa4704b9b1ff451e7bb2..2b0d70217bbdcb9bbf02bd6746b056341502ffe4 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -543,9 +543,6 @@ static int sh_pfc_probe(struct platform_device *pdev) ret = info->ops->init(pfc); if (ret < 0) return ret; - - /* .init() may have overridden pfc->info */ - info = pfc->info; } /* Enable dummy states for those platforms without pinctrl support */ diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index 42ffa8708abc6617853251d74ee55922c789f9f7..87a4f44147c1d5bcd9c286e86475b0e8370f9a86 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -1102,7 +1102,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP6_5_3, FMIN_E, SEL_FM_4), PINMUX_IPSR_DATA(IP6_7_6, AUDIO_CLKOUT), PINMUX_IPSR_MSEL(IP6_7_6, MSIOF1_SS1_B, SEL_SOF1_1), - PINMUX_IPSR_MSEL(IP6_7_6, TX2, SEL_SCIF2_0), + PINMUX_IPSR_MSEL(IP6_5_3, TX2, SEL_SCIF2_0), PINMUX_IPSR_MSEL(IP6_7_6, SCIFA2_TXD, SEL_SCIFA2_0), PINMUX_IPSR_DATA(IP6_9_8, IRQ0), PINMUX_IPSR_MSEL(IP6_9_8, SCIFB1_RXD_D, SEL_SCIFB1_3), diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c index a7c81e988656b7aa633d491f2aa7448505c8c0e1..90b973e159821c5889d95e58513bb04661bf8ff5 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c @@ -394,7 +394,7 @@ static const struct sunxi_desc_pin sun8i_a83t_pins[] = { SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 18), SUNXI_FUNCTION(0x0, "gpio_in"), SUNXI_FUNCTION(0x1, "gpio_out"), - SUNXI_FUNCTION(0x3, "spdif")), /* DOUT */ + SUNXI_FUNCTION(0x3, "owa")), /* DOUT */ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 19), SUNXI_FUNCTION(0x0, "gpio_in"), SUNXI_FUNCTION(0x1, "gpio_out")), diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 333d28e64087ca5a6991a04dfd4f783979a76eb5..66bdc593f811fcd5eb452a453817855e921a9606 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -194,7 +194,7 @@ config MSM_11AD tristate "Platform driver for 11ad chip" depends on PCI depends on PCI_MSM - default m + default y ---help--- This module adds required platform support for wireless adapter based on Qualcomm Technologies, Inc. 11ad chip, integrated into MSM platform diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 2ae2438032b7eeb6d02cf1c786b38637c1153d00..b111a59049522ba7920193450562bedad01e1968 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -1901,20 +1901,6 @@ int gsi_stop_channel(unsigned long chan_hdl) res = wait_for_completion_timeout(&ctx->compl, msecs_to_jiffies(GSI_STOP_CMD_TIMEOUT_MS)); if (res == 0) { - /* - * check channel state here in case the channel is stopped but - * the interrupt was not handled yet. - */ - val = gsi_readl(gsi_ctx->base + - GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(chan_hdl, - gsi_ctx->per.ee)); - ctx->state = (val & - GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK) >> - GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT; - if (ctx->state == GSI_CHAN_STATE_STOPPED) { - res = GSI_STATUS_SUCCESS; - goto free_lock; - } GSIDBG("chan_hdl=%lu timed out\n", chan_hdl); res = -GSI_STATUS_TIMED_OUT; goto free_lock; diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index 8142a59238555ca5f2c8ceb19f90395dd603f76d..293371b88ab9781f28deb9995241acde0a0471bf 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -902,7 +902,7 @@ int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); - if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE || + if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE || ((teth_prot == IPA_USB_RNDIS || teth_prot == IPA_USB_ECM) && teth_params == NULL) || ipa_usb_notify_cb == NULL || user_data == NULL) { @@ -1105,8 +1105,7 @@ static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params) params->xfer_scratch.depcmd_hi_addr); if (params->client >= IPA_CLIENT_MAX || - params->teth_prot < 0 || - params->teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE || + params->teth_prot > IPA_USB_MAX_TETH_PROT_SIZE || params->xfer_ring_len % GSI_CHAN_RE_SIZE_16B || params->xfer_scratch.const_buffer_size < 1 || params->xfer_scratch.const_buffer_size > 31) { @@ -1370,7 +1369,7 @@ static int ipa3_usb_release_xdci_channel(u32 clnt_hdl, int result = 0; IPA_USB_DBG_LOW("entry\n"); - if (ttype < 0 || ttype >= IPA_USB_TRANSPORT_MAX) { + if (ttype > IPA_USB_TRANSPORT_MAX) { IPA_USB_ERR("bad parameter.\n"); return -EINVAL; } @@ -1474,8 +1473,7 @@ static bool ipa3_usb_check_connect_params( (params->teth_prot != IPA_USB_DIAG && (params->usb_to_ipa_xferrscidx < 0 || params->usb_to_ipa_xferrscidx > 127)) || - params->teth_prot < 0 || - params->teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) { + params->teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) { IPA_USB_ERR("Invalid params\n"); return false; } @@ -2179,7 +2177,7 @@ EXPORT_SYMBOL(ipa_usb_xdci_connect); static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot) { - if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) { + if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) { IPA_USB_ERR("bad parameter.\n"); return -EFAULT; } @@ -2369,7 +2367,7 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot) mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); - if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) { + if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) { IPA_USB_ERR("bad parameters.\n"); result = -EINVAL; goto bad_params; @@ -2555,7 +2553,7 @@ int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); - if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) { + if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) { IPA_USB_ERR("bad parameters.\n"); result = -EINVAL; goto bad_params; @@ -2756,7 +2754,7 @@ int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); - if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) { + if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) { IPA_USB_ERR("bad parameters.\n"); result = -EINVAL; goto bad_params; diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h index d5f102eaaac641112fac9b4c695a0fc9ff467b51..981129eb9f3acf5e24f08341333418d5b4d8e142 100644 --- a/drivers/platform/msm/ipa/ipa_common_i.h +++ b/drivers/platform/msm/ipa/ipa_common_i.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -26,8 +26,7 @@ log_info.file = __FILENAME__; \ log_info.line = __LINE__; \ log_info.type = EP; \ - log_info.id_string = (client < 0 || client >= IPA_CLIENT_MAX) \ - ? "Invalid Client" : ipa_clients_strings[client] + log_info.id_string = ipa_clients_strings[client] #define IPA_ACTIVE_CLIENTS_PREP_SIMPLE(log_info) \ log_info.file = __FILENAME__; \ diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index 85fa9da50779e031274fef3b3f607a7a9a26a976..0d17fa58a853e17fc38c2d49a3a116b6a017afdb 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -641,7 +641,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_nat_dma_cmd *)param)->entries != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_nat_dma_cmd *)param)->entries, pre_entry); retval = -EFAULT; @@ -688,7 +688,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_hdr *)param)->num_hdrs, pre_entry); retval = -EFAULT; @@ -727,7 +727,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_del_hdr *)param)->num_hdls, pre_entry); retval = -EFAULT; @@ -767,7 +767,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_rt_rule *)param)-> num_rules, pre_entry); @@ -807,7 +807,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_mdfy_rt_rule *)param)-> num_rules, pre_entry); @@ -847,7 +847,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_del_rt_rule *)param)->num_hdls, pre_entry); retval = -EFAULT; @@ -886,7 +886,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_flt_rule *)param)-> num_rules, pre_entry); @@ -926,7 +926,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_del_flt_rule *)param)-> num_hdls, pre_entry); @@ -966,7 +966,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_mdfy_flt_rule *)param)-> num_rules, pre_entry); @@ -1104,7 +1104,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (unlikely(((struct ipa_ioc_query_intf_tx_props *) param)->num_tx_props != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_query_intf_tx_props *) param)->num_tx_props, pre_entry); retval = -EFAULT; @@ -1149,7 +1149,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_query_intf_rx_props *) param)->num_rx_props != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_query_intf_rx_props *) param)->num_rx_props, pre_entry); retval = -EFAULT; @@ -1194,7 +1194,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_query_intf_ext_props *) param)->num_ext_props != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_query_intf_ext_props *) param)->num_ext_props, pre_entry); retval = -EFAULT; @@ -1232,7 +1232,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_msg_meta *)param)->msg_len != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_msg_meta *)param)->msg_len, pre_entry); retval = -EFAULT; @@ -1372,7 +1372,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *) param)->num_proc_ctxs != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_hdr_proc_ctx *) param)->num_proc_ctxs, pre_entry); retval = -EFAULT; @@ -1411,7 +1411,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *) param)->num_hdls != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_del_hdr_proc_ctx *)param)-> num_hdls, pre_entry); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index cf97c6966b332af7c4d2785769b9a0fd384b8f4d..cb95f6e98956e0411441400b2062aed70886accd 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -808,11 +808,10 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, eq = true; } else { rt_tbl = ipa_id_find(entry->rule.rt_tbl_hdl); - if (rt_tbl == NULL || - rt_tbl->cookie != IPA_RT_TBL_COOKIE) - rt_tbl_idx = ~0; - else + if (rt_tbl) rt_tbl_idx = rt_tbl->idx; + else + rt_tbl_idx = ~0; bitmap = entry->rule.attrib.attrib_mask; eq = false; } @@ -839,11 +838,10 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, eq = true; } else { rt_tbl = ipa_id_find(entry->rule.rt_tbl_hdl); - if (rt_tbl == NULL || - rt_tbl->cookie != IPA_RT_TBL_COOKIE) - rt_tbl_idx = ~0; - else + if (rt_tbl) rt_tbl_idx = rt_tbl->idx; + else + rt_tbl_idx = ~0; bitmap = entry->rule.attrib.attrib_mask; eq = false; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c index 72542bf6dd5da2ef9f85da4176052b2eaa36cba3..80514f6c738ed1cf47bf91a792a86985f1accf08 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c @@ -1017,25 +1017,25 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip, if (rule->action != IPA_PASS_TO_EXCEPTION) { if (!rule->eq_attrib_type) { if (!rule->rt_tbl_hdl) { - IPAERR_RL("invalid RT tbl\n"); + IPAERR("invalid RT tbl\n"); goto error; } rt_tbl = ipa_id_find(rule->rt_tbl_hdl); if (rt_tbl == NULL) { - IPAERR_RL("RT tbl not found\n"); + IPAERR("RT tbl not found\n"); goto error; } - if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) { - IPAERR_RL("RT table cookie is invalid\n"); + if (rt_tbl->cookie != IPA_COOKIE) { + IPAERR("RT table cookie is invalid\n"); goto error; } } else { if (rule->rt_tbl_idx > ((ip == IPA_IP_v4) ? IPA_MEM_PART(v4_modem_rt_index_hi) : IPA_MEM_PART(v6_modem_rt_index_hi))) { - IPAERR_RL("invalid RT tbl\n"); + IPAERR("invalid RT tbl\n"); goto error; } } @@ -1048,7 +1048,7 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip, } INIT_LIST_HEAD(&entry->link); entry->rule = *rule; - entry->cookie = IPA_FLT_COOKIE; + entry->cookie = IPA_COOKIE; entry->rt_tbl = rt_tbl; entry->tbl = tbl; if (add_rear) { @@ -1067,19 +1067,13 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip, if (id < 0) { IPAERR("failed to add to tree\n"); WARN_ON(1); - goto ipa_insert_failed; } *rule_hdl = id; entry->id = id; IPADBG_LOW("add flt rule rule_cnt=%d\n", tbl->rule_cnt); return 0; -ipa_insert_failed: - tbl->rule_cnt--; - if (entry->rt_tbl) - entry->rt_tbl->ref_cnt--; - list_del(&entry->link); - kmem_cache_free(ipa_ctx->flt_rule_cache, entry); + error: return -EPERM; } @@ -1091,12 +1085,12 @@ static int __ipa_del_flt_rule(u32 rule_hdl) entry = ipa_id_find(rule_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); return -EINVAL; } - if (entry->cookie != IPA_FLT_COOKIE) { - IPAERR_RL("bad params\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad params\n"); return -EINVAL; } id = entry->id; @@ -1123,12 +1117,12 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule, entry = ipa_id_find(frule->rule_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); goto error; } - if (entry->cookie != IPA_FLT_COOKIE) { - IPAERR_RL("bad params\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad params\n"); goto error; } @@ -1138,25 +1132,25 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule, if (frule->rule.action != IPA_PASS_TO_EXCEPTION) { if (!frule->rule.eq_attrib_type) { if (!frule->rule.rt_tbl_hdl) { - IPAERR_RL("invalid RT tbl\n"); + IPAERR("invalid RT tbl\n"); goto error; } rt_tbl = ipa_id_find(frule->rule.rt_tbl_hdl); if (rt_tbl == NULL) { - IPAERR_RL("RT tbl not found\n"); + IPAERR("RT tbl not found\n"); goto error; } - if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) { - IPAERR_RL("RT table cookie is invalid\n"); + if (rt_tbl->cookie != IPA_COOKIE) { + IPAERR("RT table cookie is invalid\n"); goto error; } } else { if (frule->rule.rt_tbl_idx > ((ip == IPA_IP_v4) ? IPA_MEM_PART(v4_modem_rt_index_hi) : IPA_MEM_PART(v6_modem_rt_index_hi))) { - IPAERR_RL("invalid RT tbl\n"); + IPAERR("invalid RT tbl\n"); goto error; } } @@ -1180,7 +1174,7 @@ static int __ipa_add_global_flt_rule(enum ipa_ip_type ip, struct ipa_flt_tbl *tbl; if (rule == NULL || rule_hdl == NULL) { - IPAERR_RL("bad parms rule=%p rule_hdl=%p\n", rule, rule_hdl); + IPAERR("bad parms rule=%p rule_hdl=%p\n", rule, rule_hdl); return -EINVAL; } @@ -1199,14 +1193,14 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, int ipa_ep_idx; if (rule == NULL || rule_hdl == NULL || ep >= IPA_CLIENT_MAX) { - IPAERR_RL("bad parms rule=%p rule_hdl=%p ep=%d\n", rule, + IPAERR("bad parms rule=%p rule_hdl=%p ep=%d\n", rule, rule_hdl, ep); return -EINVAL; } ipa_ep_idx = ipa2_get_ep_mapping(ep); if (ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) { - IPAERR_RL("ep not valid ep=%d\n", ep); + IPAERR("ep not valid ep=%d\n", ep); return -EINVAL; } if (ipa_ctx->ep[ipa_ep_idx].valid == 0) @@ -1233,7 +1227,7 @@ int ipa2_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1251,7 +1245,7 @@ int ipa2_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) rules->rules[i].at_rear, &rules->rules[i].flt_rule_hdl); if (result) { - IPAERR_RL("failed to add flt rule %d\n", i); + IPAERR("failed to add flt rule %d\n", i); rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; @@ -1284,14 +1278,14 @@ int ipa2_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls) int result; if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa_ctx->lock); for (i = 0; i < hdls->num_hdls; i++) { if (__ipa_del_flt_rule(hdls->hdl[i].hdl)) { - IPAERR_RL("failed to del rt rule %i\n", i); + IPAERR("failed to del rt rule %i\n", i); hdls->hdl[i].status = IPA_FLT_STATUS_OF_DEL_FAILED; } else { hdls->hdl[i].status = 0; @@ -1324,14 +1318,14 @@ int ipa2_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *hdls) int result; if (hdls == NULL || hdls->num_rules == 0 || hdls->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa_ctx->lock); for (i = 0; i < hdls->num_rules; i++) { if (__ipa_mdfy_flt_rule(&hdls->rules[i], hdls->ip)) { - IPAERR_RL("failed to mdfy rt rule %i\n", i); + IPAERR("failed to mdfy rt rule %i\n", i); hdls->rules[i].status = IPA_FLT_STATUS_OF_MDFY_FAILED; } else { hdls->rules[i].status = 0; @@ -1365,7 +1359,7 @@ int ipa2_commit_flt(enum ipa_ip_type ip) int result; if (ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1401,7 +1395,7 @@ int ipa2_reset_flt(enum ipa_ip_type ip) int id; if (ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c index 49aa7f25347dfd003e13e5e10cfc45a0ccfbcab3..10a49b1e75d8944e4d611b79b53b1897be2dba42 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c @@ -547,7 +547,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, { struct ipa_hdr_entry *hdr_entry; struct ipa_hdr_proc_ctx_entry *entry; - struct ipa_hdr_proc_ctx_offset_entry *offset = NULL; + struct ipa_hdr_proc_ctx_offset_entry *offset; u32 bin; struct ipa_hdr_proc_ctx_tbl *htbl = &ipa_ctx->hdr_proc_ctx_tbl; int id; @@ -558,13 +558,13 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, proc_ctx->type, proc_ctx->hdr_hdl); if (!HDR_PROC_TYPE_IS_VALID(proc_ctx->type)) { - IPAERR_RL("invalid processing type %d\n", proc_ctx->type); + IPAERR("invalid processing type %d\n", proc_ctx->type); return -EINVAL; } hdr_entry = ipa_id_find(proc_ctx->hdr_hdl); - if (!hdr_entry || (hdr_entry->cookie != IPA_HDR_COOKIE)) { - IPAERR_RL("hdr_hdl is invalid\n"); + if (!hdr_entry || (hdr_entry->cookie != IPA_COOKIE)) { + IPAERR("hdr_hdl is invalid\n"); return -EINVAL; } @@ -580,7 +580,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, entry->hdr = hdr_entry; if (add_ref_hdr) hdr_entry->ref_cnt++; - entry->cookie = IPA_PROC_HDR_COOKIE; + entry->cookie = IPA_COOKIE; needed_len = (proc_ctx->type == IPA_HDR_PROC_NONE) ? sizeof(struct ipa_hdr_proc_ctx_add_hdr_seq) : @@ -592,7 +592,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN1]) { bin = IPA_HDR_PROC_CTX_BIN1; } else { - IPAERR_RL("unexpected needed len %d\n", needed_len); + IPAERR("unexpected needed len %d\n", needed_len); WARN_ON(1); goto bad_len; } @@ -602,7 +602,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr); if (list_empty(&htbl->head_free_offset_list[bin])) { if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) { - IPAERR_RL("hdr proc ctx table overflow\n"); + IPAERR("hdr proc ctx table overflow\n"); goto bad_len; } @@ -640,7 +640,6 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, if (id < 0) { IPAERR("failed to alloc id\n"); WARN_ON(1); - goto ipa_insert_failed; } entry->id = id; proc_ctx->proc_ctx_hdl = id; @@ -648,13 +647,6 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, return 0; -ipa_insert_failed: - list_move(&offset->link, - &htbl->head_free_offset_list[offset->bin]); - entry->offset_entry = NULL; - list_del(&entry->link); - htbl->proc_ctx_cnt--; - bad_len: if (add_ref_hdr) hdr_entry->ref_cnt--; @@ -667,7 +659,7 @@ bad_len: static int __ipa_add_hdr(struct ipa_hdr_add *hdr) { struct ipa_hdr_entry *entry; - struct ipa_hdr_offset_entry *offset = NULL; + struct ipa_hdr_offset_entry *offset; u32 bin; struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl; int id; @@ -675,12 +667,12 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0); if (hdr->hdr_len == 0 || hdr->hdr_len > IPA_HDR_MAX_SIZE) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); goto error; } if (!HDR_TYPE_IS_VALID(hdr->type)) { - IPAERR_RL("invalid hdr type %d\n", hdr->type); + IPAERR("invalid hdr type %d\n", hdr->type); goto error; } @@ -699,7 +691,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) entry->type = hdr->type; entry->is_eth2_ofst_valid = hdr->is_eth2_ofst_valid; entry->eth2_ofst = hdr->eth2_ofst; - entry->cookie = IPA_HDR_COOKIE; + entry->cookie = IPA_COOKIE; if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN0]) bin = IPA_HDR_BIN0; @@ -712,7 +704,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) else if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN4]) bin = IPA_HDR_BIN4; else { - IPAERR_RL("unexpected hdr len %d\n", hdr->hdr_len); + IPAERR("unexpected hdr len %d\n", hdr->hdr_len); goto bad_hdr_len; } @@ -788,7 +780,6 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) if (id < 0) { IPAERR("failed to alloc id\n"); WARN_ON(1); - goto ipa_insert_failed; } entry->id = id; hdr->hdr_hdl = id; @@ -813,19 +804,10 @@ fail_add_proc_ctx: entry->ref_cnt--; hdr->hdr_hdl = 0; ipa_id_remove(id); -ipa_insert_failed: - if (entry->is_hdr_proc_ctx) { - dma_unmap_single(ipa_ctx->pdev, entry->phys_base, - entry->hdr_len, DMA_TO_DEVICE); - } else { - if (offset) - list_move(&offset->link, - &htbl->head_free_offset_list[offset->bin]); - entry->offset_entry = NULL; - } htbl->hdr_cnt--; list_del(&entry->link); - + dma_unmap_single(ipa_ctx->pdev, entry->phys_base, + entry->hdr_len, DMA_TO_DEVICE); fail_dma_mapping: entry->is_hdr_proc_ctx = false; bad_hdr_len: @@ -842,8 +824,8 @@ static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, struct ipa_hdr_proc_ctx_tbl *htbl = &ipa_ctx->hdr_proc_ctx_tbl; entry = ipa_id_find(proc_ctx_hdl); - if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) { - IPAERR_RL("bad parm\n"); + if (!entry || (entry->cookie != IPA_COOKIE)) { + IPAERR("bad parm\n"); return -EINVAL; } @@ -851,7 +833,7 @@ static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, htbl->proc_ctx_cnt, entry->offset_entry->offset); if (by_user && entry->user_deleted) { - IPAERR_RL("proc_ctx already deleted by user\n"); + IPAERR("proc_ctx already deleted by user\n"); return -EINVAL; } @@ -889,12 +871,12 @@ int __ipa_del_hdr(u32 hdr_hdl, bool by_user) entry = ipa_id_find(hdr_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); return -EINVAL; } - if (entry->cookie != IPA_HDR_COOKIE) { - IPAERR_RL("bad parm\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad parm\n"); return -EINVAL; } @@ -906,7 +888,7 @@ int __ipa_del_hdr(u32 hdr_hdl, bool by_user) htbl->hdr_cnt, entry->offset_entry->offset); if (by_user && entry->user_deleted) { - IPAERR_RL("hdr already deleted by user\n"); + IPAERR("hdr already deleted by user\n"); return -EINVAL; } @@ -955,12 +937,12 @@ int ipa2_add_hdr(struct ipa_ioc_add_hdr *hdrs) int result = -EFAULT; if (unlikely(!ipa_ctx)) { - IPAERR_RL("IPA driver was not initialized\n"); + IPAERR("IPA driver was not initialized\n"); return -EINVAL; } if (hdrs == NULL || hdrs->num_hdrs == 0) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -969,7 +951,7 @@ int ipa2_add_hdr(struct ipa_ioc_add_hdr *hdrs) hdrs->num_hdrs); for (i = 0; i < hdrs->num_hdrs; i++) { if (__ipa_add_hdr(&hdrs->hdr[i])) { - IPAERR_RL("failed to add hdr %d\n", i); + IPAERR("failed to add hdr %d\n", i); hdrs->hdr[i].status = -1; } else { hdrs->hdr[i].status = 0; @@ -1010,14 +992,14 @@ int ipa2_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user) } if (hdls == NULL || hdls->num_hdls == 0) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa_ctx->lock); for (i = 0; i < hdls->num_hdls; i++) { if (__ipa_del_hdr(hdls->hdl[i].hdl, by_user)) { - IPAERR_RL("failed to del hdr %i\n", i); + IPAERR("failed to del hdr %i\n", i); hdls->hdl[i].status = -1; } else { hdls->hdl[i].status = 0; @@ -1066,13 +1048,13 @@ int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) if (ipa_ctx->ipa_hw_type <= IPA_HW_v2_0 || ipa_ctx->ipa_hw_type == IPA_HW_v2_6L) { - IPAERR_RL("Processing context not supported on IPA HW %d\n", + IPAERR("Processing context not supported on IPA HW %d\n", ipa_ctx->ipa_hw_type); return -EFAULT; } if (proc_ctxs == NULL || proc_ctxs->num_proc_ctxs == 0) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1081,7 +1063,7 @@ int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) proc_ctxs->num_proc_ctxs); for (i = 0; i < proc_ctxs->num_proc_ctxs; i++) { if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], true)) { - IPAERR_RL("failed to add hdr pric ctx %d\n", i); + IPAERR("failed to add hdr pric ctx %d\n", i); proc_ctxs->proc_ctx[i].status = -1; } else { proc_ctxs->proc_ctx[i].status = 0; @@ -1126,14 +1108,14 @@ int ipa2_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls, } if (hdls == NULL || hdls->num_hdls == 0) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa_ctx->lock); for (i = 0; i < hdls->num_hdls; i++) { if (__ipa_del_hdr_proc_ctx(hdls->hdl[i].hdl, true, by_user)) { - IPAERR_RL("failed to del hdr %i\n", i); + IPAERR("failed to del hdr %i\n", i); hdls->hdl[i].status = -1; } else { hdls->hdl[i].status = 0; @@ -1370,7 +1352,7 @@ int ipa2_get_hdr(struct ipa_ioc_get_hdr *lookup) } if (lookup == NULL) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa_ctx->lock); @@ -1457,13 +1439,13 @@ int ipa2_put_hdr(u32 hdr_hdl) entry = ipa_id_find(hdr_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); result = -EINVAL; goto bail; } - if (entry->cookie != IPA_HDR_COOKIE) { - IPAERR_RL("invalid header entry\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("invalid header entry\n"); result = -EINVAL; goto bail; } @@ -1491,7 +1473,7 @@ int ipa2_copy_hdr(struct ipa_ioc_copy_hdr *copy) int result = -EFAULT; if (copy == NULL) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa_ctx->lock); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index bfb1ce56412c292d8a7842247ce0d851b098aab6..bb11230c960a06c9fbb1df42129fe4237e4eba62 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -37,15 +37,7 @@ #define DRV_NAME "ipa" #define NAT_DEV_NAME "ipaNatTable" - #define IPA_COOKIE 0x57831603 -#define IPA_RT_RULE_COOKIE 0x57831604 -#define IPA_RT_TBL_COOKIE 0x57831605 -#define IPA_FLT_COOKIE 0x57831606 -#define IPA_HDR_COOKIE 0x57831607 -#define IPA_PROC_HDR_COOKIE 0x57831608 - - #define MTU_BYTE 1500 #define IPA_MAX_NUM_PIPES 0x14 @@ -95,18 +87,6 @@ } \ } while (0) -#define IPAERR_RL(fmt, args...) \ - do { \ - pr_err_ratelimited(DRV_NAME " %s:%d " fmt, __func__, \ - __LINE__, ## args);\ - if (ipa_ctx) { \ - IPA_IPC_LOGGING(ipa_ctx->logbuf, \ - DRV_NAME " %s:%d " fmt, ## args); \ - IPA_IPC_LOGGING(ipa_ctx->logbuf_low, \ - DRV_NAME " %s:%d " fmt, ## args); \ - } \ - } while (0) - #define WLAN_AMPDU_TX_EP 15 #define WLAN_PROD_TX_EP 19 #define WLAN1_CONS_RX_EP 14 @@ -243,8 +223,8 @@ struct ipa_smmu_cb_ctx { */ struct ipa_flt_entry { struct list_head link; - u32 cookie; struct ipa_flt_rule rule; + u32 cookie; struct ipa_flt_tbl *tbl; struct ipa_rt_tbl *rt_tbl; u32 hw_len; @@ -269,13 +249,13 @@ struct ipa_flt_entry { */ struct ipa_rt_tbl { struct list_head link; - u32 cookie; struct list_head head_rt_rule_list; char name[IPA_RESOURCE_NAME_MAX]; u32 idx; u32 rule_cnt; u32 ref_cnt; struct ipa_rt_tbl_set *set; + u32 cookie; bool in_sys; u32 sz; struct ipa_mem_buffer curr_mem; @@ -306,7 +286,6 @@ struct ipa_rt_tbl { */ struct ipa_hdr_entry { struct list_head link; - u32 cookie; u8 hdr[IPA_HDR_MAX_SIZE]; u32 hdr_len; char name[IPA_RESOURCE_NAME_MAX]; @@ -316,6 +295,7 @@ struct ipa_hdr_entry { dma_addr_t phys_base; struct ipa_hdr_proc_ctx_entry *proc_ctx; struct ipa_hdr_offset_entry *offset_entry; + u32 cookie; u32 ref_cnt; int id; u8 is_eth2_ofst_valid; @@ -388,10 +368,10 @@ struct ipa_hdr_proc_ctx_add_hdr_cmd_seq { */ struct ipa_hdr_proc_ctx_entry { struct list_head link; - u32 cookie; enum ipa_hdr_proc_type type; struct ipa_hdr_proc_ctx_offset_entry *offset_entry; struct ipa_hdr_entry *hdr; + u32 cookie; u32 ref_cnt; int id; bool user_deleted; @@ -447,8 +427,8 @@ struct ipa_flt_tbl { */ struct ipa_rt_entry { struct list_head link; - u32 cookie; struct ipa_rt_rule rule; + u32 cookie; struct ipa_rt_tbl *tbl; struct ipa_hdr_entry *hdr; struct ipa_hdr_proc_ctx_entry *proc_ctx; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c index 9c4fc0ce8cc1837840d7b9146fb44811bce326d4..e3f987d47692d96395ef37991af9d23e4bd0e48e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c @@ -274,7 +274,7 @@ int ipa_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx) if (!strncmp(entry->name, tx->name, IPA_RESOURCE_NAME_MAX)) { /* add the entry check */ if (entry->num_tx_props != tx->num_tx_props) { - IPAERR_RL("invalid entry number(%u %u)\n", + IPAERR("invalid entry number(%u %u)\n", entry->num_tx_props, tx->num_tx_props); mutex_unlock(&ipa_ctx->lock); @@ -315,7 +315,7 @@ int ipa_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx) if (!strncmp(entry->name, rx->name, IPA_RESOURCE_NAME_MAX)) { /* add the entry check */ if (entry->num_rx_props != rx->num_rx_props) { - IPAERR_RL("invalid entry number(%u %u)\n", + IPAERR("invalid entry number(%u %u)\n", entry->num_rx_props, rx->num_rx_props); mutex_unlock(&ipa_ctx->lock); @@ -356,7 +356,7 @@ int ipa_query_intf_ext_props(struct ipa_ioc_query_intf_ext_props *ext) if (!strcmp(entry->name, ext->name)) { /* add the entry check */ if (entry->num_ext_props != ext->num_ext_props) { - IPAERR_RL("invalid entry number(%u %u)\n", + IPAERR("invalid entry number(%u %u)\n", entry->num_ext_props, ext->num_ext_props); mutex_unlock(&ipa_ctx->lock); @@ -405,13 +405,13 @@ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff, if (meta == NULL || (buff == NULL && callback != NULL) || (buff != NULL && callback == NULL)) { - IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n", + IPAERR("invalid param meta=%p buff=%p, callback=%p\n", meta, buff, callback); return -EINVAL; } if (meta->msg_type >= IPA_EVENT_MAX_NUM) { - IPAERR_RL("unsupported message type %d\n", meta->msg_type); + IPAERR("unsupported message type %d\n", meta->msg_type); return -EINVAL; } @@ -634,7 +634,7 @@ int ipa_pull_msg(struct ipa_msg_meta *meta, char *buff, size_t count) int result = -EINVAL; if (meta == NULL || buff == NULL || !count) { - IPAERR_RL("invalid param name=%p buff=%p count=%zu\n", + IPAERR("invalid param name=%p buff=%p count=%zu\n", meta, buff, count); return result; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c index e7092e9acbc746cd453ba9e8fa310ff902de6ce2..5dd8b225217d53ae205bbc2d887b3137604d2e65 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c @@ -252,8 +252,8 @@ int ipa2_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem) mutex_lock(&nat_ctx->lock); if (strcmp(mem->dev_name, NAT_DEV_NAME)) { - IPAERR_RL("Nat device name mismatch\n"); - IPAERR_RL("Expect: %s Recv: %s\n", NAT_DEV_NAME, mem->dev_name); + IPAERR("Nat device name mismatch\n"); + IPAERR("Expect: %s Recv: %s\n", NAT_DEV_NAME, mem->dev_name); result = -EPERM; goto bail; } @@ -272,7 +272,7 @@ int ipa2_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem) if (mem->size <= 0 || nat_ctx->is_dev_init == true) { - IPAERR_RL("Invalid Parameters or device is already init\n"); + IPAERR("Invalid Parameters or device is already init\n"); result = -EPERM; goto bail; } @@ -335,17 +335,17 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) /* check for integer overflow */ if (init->ipv4_rules_offset > - (UINT_MAX - (TBL_ENTRY_SIZE * (init->table_entries + 1)))) { - IPAERR_RL("Detected overflow\n"); - return -EPERM; + UINT_MAX - (TBL_ENTRY_SIZE * (init->table_entries + 1))) { + IPAERR("Detected overflow\n"); + return -EPERM; } /* Check Table Entry offset is not beyond allocated size */ tmp = init->ipv4_rules_offset + (TBL_ENTRY_SIZE * (init->table_entries + 1)); if (tmp > ipa_ctx->nat_mem.size) { - IPAERR_RL("Table rules offset not valid\n"); - IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", + IPAERR("Table rules offset not valid\n"); + IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->ipv4_rules_offset, (init->table_entries + 1), tmp, ipa_ctx->nat_mem.size); return -EPERM; @@ -354,16 +354,16 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) /* check for integer overflow */ if (init->expn_rules_offset > UINT_MAX - (TBL_ENTRY_SIZE * init->expn_table_entries)) { - IPAERR_RL("Detected overflow\n"); - return -EPERM; + IPAERR("Detected overflow\n"); + return -EPERM; } /* Check Expn Table Entry offset is not beyond allocated size */ tmp = init->expn_rules_offset + (TBL_ENTRY_SIZE * init->expn_table_entries); if (tmp > ipa_ctx->nat_mem.size) { - IPAERR_RL("Expn Table rules offset not valid\n"); - IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", + IPAERR("Expn Table rules offset not valid\n"); + IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->expn_rules_offset, init->expn_table_entries, tmp, ipa_ctx->nat_mem.size); return -EPERM; @@ -372,16 +372,16 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) /* check for integer overflow */ if (init->index_offset > UINT_MAX - (INDX_TBL_ENTRY_SIZE * (init->table_entries + 1))) { - IPAERR_RL("Detected overflow\n"); - return -EPERM; + IPAERR("Detected overflow\n"); + return -EPERM; } /* Check Indx Table Entry offset is not beyond allocated size */ tmp = init->index_offset + (INDX_TBL_ENTRY_SIZE * (init->table_entries + 1)); if (tmp > ipa_ctx->nat_mem.size) { - IPAERR_RL("Indx Table rules offset not valid\n"); - IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", + IPAERR("Indx Table rules offset not valid\n"); + IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->index_offset, (init->table_entries + 1), tmp, ipa_ctx->nat_mem.size); return -EPERM; @@ -389,17 +389,17 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) /* check for integer overflow */ if (init->index_expn_offset > - (UINT_MAX - (INDX_TBL_ENTRY_SIZE * init->expn_table_entries))) { - IPAERR_RL("Detected overflow\n"); - return -EPERM; + UINT_MAX - (INDX_TBL_ENTRY_SIZE * init->expn_table_entries)) { + IPAERR("Detected overflow\n"); + return -EPERM; } /* Check Expn Table entry offset is not beyond allocated size */ tmp = init->index_expn_offset + (INDX_TBL_ENTRY_SIZE * init->expn_table_entries); if (tmp > ipa_ctx->nat_mem.size) { - IPAERR_RL("Indx Expn Table rules offset not valid\n"); - IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", + IPAERR("Indx Expn Table rules offset not valid\n"); + IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->index_expn_offset, init->expn_table_entries, tmp, ipa_ctx->nat_mem.size); return -EPERM; @@ -444,16 +444,16 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) (init->expn_rules_offset > offset) || (init->index_offset > offset) || (init->index_expn_offset > offset)) { - IPAERR_RL("Failed due to integer overflow\n"); - IPAERR_RL("nat.mem.dma_handle: 0x%pa\n", + IPAERR("Failed due to integer overflow\n"); + IPAERR("nat.mem.dma_handle: 0x%pa\n", &ipa_ctx->nat_mem.dma_handle); - IPAERR_RL("ipv4_rules_offset: 0x%x\n", + IPAERR("ipv4_rules_offset: 0x%x\n", init->ipv4_rules_offset); - IPAERR_RL("expn_rules_offset: 0x%x\n", + IPAERR("expn_rules_offset: 0x%x\n", init->expn_rules_offset); - IPAERR_RL("index_offset: 0x%x\n", + IPAERR("index_offset: 0x%x\n", init->index_offset); - IPAERR_RL("index_expn_offset: 0x%x\n", + IPAERR("index_expn_offset: 0x%x\n", init->index_expn_offset); result = -EPERM; goto free_mem; @@ -509,7 +509,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) desc[1].len = size; IPADBG("posting v4 init command\n"); if (ipa_send_cmd(2, desc)) { - IPAERR_RL("Fail to send immediate command\n"); + IPAERR("Fail to send immediate command\n"); result = -EPERM; goto free_mem; } @@ -574,7 +574,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) IPADBG("\n"); if (dma->entries <= 0) { - IPAERR_RL("Invalid number of commands %d\n", + IPAERR("Invalid number of commands %d\n", dma->entries); ret = -EPERM; goto bail; @@ -582,7 +582,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) for (cnt = 0; cnt < dma->entries; cnt++) { if (dma->dma[cnt].table_index >= 1) { - IPAERR_RL("Invalid table index %d\n", + IPAERR("Invalid table index %d\n", dma->dma[cnt].table_index); ret = -EPERM; goto bail; @@ -593,7 +593,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) if (dma->dma[cnt].offset >= (ipa_ctx->nat_mem.size_base_tables + 1) * NAT_TABLE_ENTRY_SIZE_BYTE) { - IPAERR_RL("Invalid offset %d\n", + IPAERR("Invalid offset %d\n", dma->dma[cnt].offset); ret = -EPERM; goto bail; @@ -605,7 +605,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) if (dma->dma[cnt].offset >= ipa_ctx->nat_mem.size_expansion_tables * NAT_TABLE_ENTRY_SIZE_BYTE) { - IPAERR_RL("Invalid offset %d\n", + IPAERR("Invalid offset %d\n", dma->dma[cnt].offset); ret = -EPERM; goto bail; @@ -617,7 +617,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) if (dma->dma[cnt].offset >= (ipa_ctx->nat_mem.size_base_tables + 1) * NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) { - IPAERR_RL("Invalid offset %d\n", + IPAERR("Invalid offset %d\n", dma->dma[cnt].offset); ret = -EPERM; goto bail; @@ -629,7 +629,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) if (dma->dma[cnt].offset >= ipa_ctx->nat_mem.size_expansion_tables * NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) { - IPAERR_RL("Invalid offset %d\n", + IPAERR("Invalid offset %d\n", dma->dma[cnt].offset); ret = -EPERM; goto bail; @@ -638,7 +638,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) break; default: - IPAERR_RL("Invalid base_addr %d\n", + IPAERR("Invalid base_addr %d\n", dma->dma[cnt].base_addr); ret = -EPERM; goto bail; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service_v01.c b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service_v01.c index 5228b2db14100786839b25cc4b358e3e0d297cb6..dd591407d10f71e551294087038ac36ba72a04ad 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service_v01.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service_v01.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1435,66 +1435,6 @@ struct elem_info ipa_fltr_installed_notif_req_msg_data_v01_ei[] = { struct ipa_fltr_installed_notif_req_msg_v01, start_ipv6_filter_idx), }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x17, - .offset = offsetof( - struct ipa_fltr_installed_notif_req_msg_v01, - rule_id_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x17, - .offset = offsetof( - struct ipa_fltr_installed_notif_req_msg_v01, - rule_id_len), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = QMI_IPA_MAX_FILTERS_V01, - .elem_size = sizeof(uint32_t), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x17, - .offset = offsetof( - struct ipa_fltr_installed_notif_req_msg_v01, - rule_id), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x18, - .offset = offsetof( - struct ipa_fltr_installed_notif_req_msg_v01, - dst_pipe_id_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x18, - .offset = offsetof( - struct ipa_fltr_installed_notif_req_msg_v01, - dst_pipe_id_len), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = QMI_IPA_MAX_CLIENT_DST_PIPES_V01, - .elem_size = sizeof(uint32_t), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x18, - .offset = offsetof( - struct ipa_fltr_installed_notif_req_msg_v01, - dst_pipe_id), - }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c index 293a60a60881e004de7f2324becc8784bfb9edcf..f2909110d09f45606ddcc84c5b12f880c30ab4bf 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c @@ -53,7 +53,7 @@ int __ipa_generate_rt_hw_rule_v2(enum ipa_ip_type ip, int pipe_idx; if (buf == NULL) { - memset(tmp, 0, (IPA_RT_FLT_HW_RULE_BUF_SIZE/4)); + memset(tmp, 0, IPA_RT_FLT_HW_RULE_BUF_SIZE); buf = (u8 *)tmp; } @@ -75,15 +75,8 @@ int __ipa_generate_rt_hw_rule_v2(enum ipa_ip_type ip, rule_hdr->u.hdr.pipe_dest_idx = pipe_idx; rule_hdr->u.hdr.system = !ipa_ctx->hdr_tbl_lcl; if (entry->hdr) { - if (entry->hdr->cookie == IPA_HDR_COOKIE) { - rule_hdr->u.hdr.hdr_offset = - entry->hdr->offset_entry->offset >> 2; - } else { - IPAERR("Entry hdr deleted by user = %d cookie = %u\n", - entry->hdr->user_deleted, entry->hdr->cookie); - WARN_ON(1); - rule_hdr->u.hdr.hdr_offset = 0; - } + rule_hdr->u.hdr.hdr_offset = + entry->hdr->offset_entry->offset >> 2; } else { rule_hdr->u.hdr.hdr_offset = 0; } @@ -860,7 +853,7 @@ int ipa2_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in) struct ipa_rt_tbl *entry; if (in->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -916,7 +909,7 @@ static struct ipa_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip, INIT_LIST_HEAD(&entry->link); strlcpy(entry->name, name, IPA_RESOURCE_NAME_MAX); entry->set = set; - entry->cookie = IPA_RT_TBL_COOKIE; + entry->cookie = IPA_COOKIE; entry->in_sys = (ip == IPA_IP_v4) ? !ipa_ctx->ip4_rt_tbl_lcl : !ipa_ctx->ip6_rt_tbl_lcl; set->tbl_cnt++; @@ -929,16 +922,12 @@ static struct ipa_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip, if (id < 0) { IPAERR("failed to add to tree\n"); WARN_ON(1); - goto ipa_insert_failed; } entry->id = id; } return entry; -ipa_insert_failed: - set->tbl_cnt--; - list_del(&entry->link); fail_rt_idx_alloc: entry->cookie = 0; kmem_cache_free(ipa_ctx->rt_tbl_cache, entry); @@ -951,13 +940,13 @@ static int __ipa_del_rt_tbl(struct ipa_rt_tbl *entry) enum ipa_ip_type ip = IPA_IP_MAX; u32 id; - if (entry == NULL || (entry->cookie != IPA_RT_TBL_COOKIE)) { - IPAERR_RL("bad parms\n"); + if (entry == NULL || (entry->cookie != IPA_COOKIE)) { + IPAERR("bad parms\n"); return -EINVAL; } id = entry->id; if (ipa_id_find(id) == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); return -EPERM; } @@ -965,11 +954,8 @@ static int __ipa_del_rt_tbl(struct ipa_rt_tbl *entry) ip = IPA_IP_v4; else if (entry->set == &ipa_ctx->rt_tbl_set[IPA_IP_v6]) ip = IPA_IP_v6; - else { + else WARN_ON(1); - return -EPERM; - } - if (!entry->in_sys) { list_del(&entry->link); @@ -1008,14 +994,13 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, if (rule->hdr_hdl) { hdr = ipa_id_find(rule->hdr_hdl); - if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) { + if ((hdr == NULL) || (hdr->cookie != IPA_COOKIE)) { IPAERR("rt rule does not point to valid hdr\n"); goto error; } } else if (rule->hdr_proc_ctx_hdl) { proc_ctx = ipa_id_find(rule->hdr_proc_ctx_hdl); - if ((proc_ctx == NULL) || - (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) { + if ((proc_ctx == NULL) || (proc_ctx->cookie != IPA_COOKIE)) { IPAERR("rt rule does not point to valid proc ctx\n"); goto error; } @@ -1023,7 +1008,7 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, tbl = __ipa_add_rt_tbl(ip, name); - if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) { + if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) { IPAERR("bad params\n"); goto error; } @@ -1044,7 +1029,7 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, goto error; } INIT_LIST_HEAD(&entry->link); - entry->cookie = IPA_RT_RULE_COOKIE; + entry->cookie = IPA_COOKIE; entry->rule = *rule; entry->tbl = tbl; entry->hdr = hdr; @@ -1097,7 +1082,7 @@ int ipa2_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) int ret; if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1107,7 +1092,7 @@ int ipa2_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) &rules->rules[i].rule, rules->rules[i].at_rear, &rules->rules[i].rt_rule_hdl)) { - IPAERR_RL("failed to add rt rule %d\n", i); + IPAERR("failed to add rt rule %d\n", i); rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; @@ -1134,12 +1119,12 @@ int __ipa_del_rt_rule(u32 rule_hdl) entry = ipa_id_find(rule_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); return -EINVAL; } - if (entry->cookie != IPA_RT_RULE_COOKIE) { - IPAERR_RL("bad params\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad params\n"); return -EINVAL; } @@ -1153,7 +1138,7 @@ int __ipa_del_rt_rule(u32 rule_hdl) entry->tbl->rule_cnt); if (entry->tbl->rule_cnt == 0 && entry->tbl->ref_cnt == 0) { if (__ipa_del_rt_tbl(entry->tbl)) - IPAERR_RL("fail to del RT tbl\n"); + IPAERR("fail to del RT tbl\n"); } entry->cookie = 0; id = entry->id; @@ -1180,14 +1165,14 @@ int ipa2_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls) int ret; if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa_ctx->lock); for (i = 0; i < hdls->num_hdls; i++) { if (__ipa_del_rt_rule(hdls->hdl[i].hdl)) { - IPAERR_RL("failed to del rt rule %i\n", i); + IPAERR("failed to del rt rule %i\n", i); hdls->hdl[i].status = IPA_RT_STATUS_OF_DEL_FAILED; } else { hdls->hdl[i].status = 0; @@ -1220,7 +1205,7 @@ int ipa2_commit_rt(enum ipa_ip_type ip) int ret; if (ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1264,7 +1249,7 @@ int ipa2_reset_rt(enum ipa_ip_type ip) int id; if (ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1282,7 +1267,7 @@ int ipa2_reset_rt(enum ipa_ip_type ip) * filtering rules point to routing tables */ if (ipa2_reset_flt(ip)) - IPAERR_RL("fail to reset flt ip=%d\n", ip); + IPAERR("fail to reset flt ip=%d\n", ip); set = &ipa_ctx->rt_tbl_set[ip]; rset = &ipa_ctx->reap_rt_tbl_set[ip]; @@ -1368,14 +1353,14 @@ int ipa2_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup) int result = -EFAULT; if (lookup == NULL || lookup->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa_ctx->lock); entry = __ipa_find_rt_tbl(lookup->ip, lookup->name); - if (entry && entry->cookie == IPA_RT_TBL_COOKIE) { + if (entry && entry->cookie == IPA_COOKIE) { if (entry->ref_cnt == U32_MAX) { - IPAERR_RL("fail: ref count crossed limit\n"); + IPAERR("fail: ref count crossed limit\n"); goto ret; } entry->ref_cnt++; @@ -1383,7 +1368,7 @@ int ipa2_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup) /* commit for get */ if (ipa_ctx->ctrl->ipa_commit_rt(lookup->ip)) - IPAERR_RL("fail to commit RT tbl\n"); + IPAERR("fail to commit RT tbl\n"); result = 0; } @@ -1406,18 +1391,18 @@ int ipa2_put_rt_tbl(u32 rt_tbl_hdl) { struct ipa_rt_tbl *entry; enum ipa_ip_type ip = IPA_IP_MAX; - int result = 0; + int result; mutex_lock(&ipa_ctx->lock); entry = ipa_id_find(rt_tbl_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); result = -EINVAL; goto ret; } - if ((entry->cookie != IPA_RT_TBL_COOKIE) || entry->ref_cnt == 0) { - IPAERR_RL("bad parms\n"); + if ((entry->cookie != IPA_COOKIE) || entry->ref_cnt == 0) { + IPAERR("bad parms\n"); result = -EINVAL; goto ret; } @@ -1426,19 +1411,16 @@ int ipa2_put_rt_tbl(u32 rt_tbl_hdl) ip = IPA_IP_v4; else if (entry->set == &ipa_ctx->rt_tbl_set[IPA_IP_v6]) ip = IPA_IP_v6; - else { + else WARN_ON(1); - result = -EINVAL; - goto ret; - } entry->ref_cnt--; if (entry->ref_cnt == 0 && entry->rule_cnt == 0) { if (__ipa_del_rt_tbl(entry)) - IPAERR_RL("fail to del RT tbl\n"); + IPAERR("fail to del RT tbl\n"); /* commit for put */ if (ipa_ctx->ctrl->ipa_commit_rt(ip)) - IPAERR_RL("fail to commit RT tbl\n"); + IPAERR("fail to commit RT tbl\n"); } result = 0; @@ -1457,20 +1439,20 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) if (rtrule->rule.hdr_hdl) { hdr = ipa_id_find(rtrule->rule.hdr_hdl); - if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) { - IPAERR_RL("rt rule does not point to valid hdr\n"); + if ((hdr == NULL) || (hdr->cookie != IPA_COOKIE)) { + IPAERR("rt rule does not point to valid hdr\n"); goto error; } } entry = ipa_id_find(rtrule->rt_rule_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); goto error; } - if (entry->cookie != IPA_RT_RULE_COOKIE) { - IPAERR_RL("bad params\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad params\n"); goto error; } @@ -1503,14 +1485,14 @@ int ipa2_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *hdls) int result; if (hdls == NULL || hdls->num_rules == 0 || hdls->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa_ctx->lock); for (i = 0; i < hdls->num_rules; i++) { if (__ipa_mdfy_rt_rule(&hdls->rules[i])) { - IPAERR_RL("failed to mdfy rt rule %i\n", i); + IPAERR("failed to mdfy rt rule %i\n", i); hdls->rules[i].status = IPA_RT_STATUS_OF_MDFY_FAILED; } else { hdls->rules[i].status = 0; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c index 23f802425cf0af0662f9174bbb692136d57a45c3..56b4bf1a2d1e490e9eaeedc51d196f82a6cd1d75 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c @@ -1672,7 +1672,7 @@ int ipa_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id) if (clnt_hdl >= ipa_ctx->ipa_num_pipes || ipa_ctx->ep[clnt_hdl].valid == 0) { - IPAERR_RL("bad parm, %d\n", clnt_hdl); + IPAERR("bad parm, %d\n", clnt_hdl); return -EINVAL; } @@ -1685,7 +1685,7 @@ int ipa_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id) ep = &ipa_ctx->ep[clnt_hdl]; if (!(ep->uc_offload_state & IPA_WDI_CONNECTED)) { - IPAERR_RL("WDI channel bad state %d\n", ep->uc_offload_state); + IPAERR("WDI channel bad state %d\n", ep->uc_offload_state); return -EFAULT; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index 50a8e46d3b12744cff75b20dc47a009381930416..e0200fe5087150a77fd520646b1f3ef02b0c12fd 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -918,7 +918,7 @@ int ipa2_get_ep_mapping(enum ipa_client_type client) } if (client >= IPA_CLIENT_MAX || client < 0) { - IPAERR_RL("Bad client number! client =%d\n", client); + IPAERR("Bad client number! client =%d\n", client); return INVALID_EP_MAPPING_INDEX; } @@ -1769,7 +1769,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_NEXT_HDR || attrib->attrib_mask & IPA_FLT_TC || attrib->attrib_mask & IPA_FLT_FLOW_LABEL) { - IPAERR_RL("v6 attrib's specified for v4 rule\n"); + IPAERR("v6 attrib's specified for v4 rule\n"); return -EPERM; } @@ -1781,7 +1781,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) { if (ipa_ofst_meq32[ofst_meq32] == -1) { - IPAERR_RL("ran out of meq32 eq\n"); + IPAERR("ran out of meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq32[ofst_meq32]; @@ -1801,7 +1801,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) { if (ipa_ofst_meq32[ofst_meq32] == -1) { - IPAERR_RL("ran out of meq32 eq\n"); + IPAERR("ran out of meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq32[ofst_meq32]; @@ -1815,7 +1815,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_DST_ADDR) { if (ipa_ofst_meq32[ofst_meq32] == -1) { - IPAERR_RL("ran out of meq32 eq\n"); + IPAERR("ran out of meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq32[ofst_meq32]; @@ -1829,11 +1829,11 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { - IPAERR_RL("ran out of ihl_rng16 eq\n"); + IPAERR("ran out of ihl_rng16 eq\n"); return -EPERM; } if (attrib->src_port_hi < attrib->src_port_lo) { - IPAERR_RL("bad src port range param\n"); + IPAERR("bad src port range param\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16]; @@ -1847,11 +1847,11 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { - IPAERR_RL("ran out of ihl_rng16 eq\n"); + IPAERR("ran out of ihl_rng16 eq\n"); return -EPERM; } if (attrib->dst_port_hi < attrib->dst_port_lo) { - IPAERR_RL("bad dst port range param\n"); + IPAERR("bad dst port range param\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16]; @@ -1865,7 +1865,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_TYPE) { if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { - IPAERR_RL("ran out of ihl_meq32 eq\n"); + IPAERR("ran out of ihl_meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; @@ -1878,7 +1878,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_CODE) { if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { - IPAERR_RL("ran out of ihl_meq32 eq\n"); + IPAERR("ran out of ihl_meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; @@ -1891,7 +1891,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_SPI) { if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { - IPAERR_RL("ran out of ihl_meq32 eq\n"); + IPAERR("ran out of ihl_meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; @@ -1905,7 +1905,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_SRC_PORT) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { - IPAERR_RL("ran out of ihl_rng16 eq\n"); + IPAERR("ran out of ihl_rng16 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16]; @@ -1919,7 +1919,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_DST_PORT) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { - IPAERR_RL("ran out of ihl_rng16 eq\n"); + IPAERR("ran out of ihl_rng16 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16]; @@ -1946,7 +1946,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_ETHER_II) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -1961,7 +1961,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_ETHER_II) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -1976,7 +1976,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_3) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -1991,7 +1991,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_3) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -2006,7 +2006,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) { if (ipa_ofst_meq32[ofst_meq32] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq32[ofst_meq32]; @@ -2024,7 +2024,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, /* error check */ if (attrib->attrib_mask & IPA_FLT_TOS || attrib->attrib_mask & IPA_FLT_PROTOCOL) { - IPAERR_RL("v4 attrib's specified for v6 rule\n"); + IPAERR("v4 attrib's specified for v6 rule\n"); return -EPERM; } @@ -2036,7 +2036,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_TYPE) { if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { - IPAERR_RL("ran out of ihl_meq32 eq\n"); + IPAERR("ran out of ihl_meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; @@ -2049,7 +2049,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_CODE) { if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { - IPAERR_RL("ran out of ihl_meq32 eq\n"); + IPAERR("ran out of ihl_meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; @@ -2062,7 +2062,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_SPI) { if (ipa_ihl_ofst_meq32[ihl_ofst_meq32] == -1) { - IPAERR_RL("ran out of ihl_meq32 eq\n"); + IPAERR("ran out of ihl_meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_meq32[ihl_ofst_meq32]; @@ -2076,7 +2076,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_SRC_PORT) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { - IPAERR_RL("ran out of ihl_rng16 eq\n"); + IPAERR("ran out of ihl_rng16 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16]; @@ -2090,7 +2090,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_DST_PORT) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { - IPAERR_RL("ran out of ihl_rng16 eq\n"); + IPAERR("ran out of ihl_rng16 eq\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16]; @@ -2104,11 +2104,11 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { - IPAERR_RL("ran out of ihl_rng16 eq\n"); + IPAERR("ran out of ihl_rng16 eq\n"); return -EPERM; } if (attrib->src_port_hi < attrib->src_port_lo) { - IPAERR_RL("bad src port range param\n"); + IPAERR("bad src port range param\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16]; @@ -2122,11 +2122,11 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) { if (ipa_ihl_ofst_rng16[ihl_ofst_rng16] == -1) { - IPAERR_RL("ran out of ihl_rng16 eq\n"); + IPAERR("ran out of ihl_rng16 eq\n"); return -EPERM; } if (attrib->dst_port_hi < attrib->dst_port_lo) { - IPAERR_RL("bad dst port range param\n"); + IPAERR("bad dst port range param\n"); return -EPERM; } *en_rule |= ipa_ihl_ofst_rng16[ihl_ofst_rng16]; @@ -2140,7 +2140,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -2166,7 +2166,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_DST_ADDR) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -2198,7 +2198,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -2243,7 +2243,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_ETHER_II) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -2258,7 +2258,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_ETHER_II) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -2273,7 +2273,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_3) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -2288,7 +2288,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_3) { if (ipa_ofst_meq128[ofst_meq128] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq128[ofst_meq128]; @@ -2303,7 +2303,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) { if (ipa_ofst_meq32[ofst_meq32] == -1) { - IPAERR_RL("ran out of meq128 eq\n"); + IPAERR("ran out of meq128 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq32[ofst_meq32]; @@ -2316,7 +2316,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, } } else { - IPAERR_RL("unsupported ip %d\n", ip); + IPAERR("unsupported ip %d\n", ip); return -EPERM; } @@ -2326,7 +2326,7 @@ int ipa_generate_flt_eq(enum ipa_ip_type ip, */ if (attrib->attrib_mask == 0) { if (ipa_ofst_meq32[ofst_meq32] == -1) { - IPAERR_RL("ran out of meq32 eq\n"); + IPAERR("ran out of meq32 eq\n"); return -EPERM; } *en_rule |= ipa_ofst_meq32[ofst_meq32]; @@ -3617,19 +3617,19 @@ int ipa2_write_qmap_id(struct ipa_ioc_write_qmapid *param_in) } if (param_in->client >= IPA_CLIENT_MAX) { - IPAERR_RL("bad parm client:%d\n", param_in->client); + IPAERR("bad parm client:%d\n", param_in->client); goto fail; } ipa_ep_idx = ipa2_get_ep_mapping(param_in->client); if (ipa_ep_idx == -1) { - IPAERR_RL("Invalid client.\n"); + IPAERR("Invalid client.\n"); goto fail; } ep = &ipa_ctx->ep[ipa_ep_idx]; if (!ep->valid) { - IPAERR_RL("EP not allocated.\n"); + IPAERR("EP not allocated.\n"); goto fail; } @@ -3642,7 +3642,7 @@ int ipa2_write_qmap_id(struct ipa_ioc_write_qmapid *param_in) ipa_ctx->ep[ipa_ep_idx].cfg.meta = meta; result = ipa_write_qmapid_wdi_pipe(ipa_ep_idx, meta.qmap_id); if (result) - IPAERR_RL("qmap_id %d write failed on ep=%d\n", + IPAERR("qmap_id %d write failed on ep=%d\n", meta.qmap_id, ipa_ep_idx); result = 0; } diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index c3ff8981effd278bfa8147c378fb61401fbeeda8..834712a71ac629214cd2716a08885bbca801e446 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -411,15 +411,12 @@ int copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01 { int i, j; - /* prevent multi-threads accessing num_q6_rule */ - mutex_lock(&add_mux_channel_lock); if (rule_req->filter_spec_list_valid == true) { num_q6_rule = rule_req->filter_spec_list_len; IPAWANDBG("Received (%d) install_flt_req\n", num_q6_rule); } else { num_q6_rule = 0; IPAWANERR("got no UL rules from modem\n"); - mutex_unlock(&add_mux_channel_lock); return -EINVAL; } @@ -613,11 +610,9 @@ failure: num_q6_rule = 0; memset(ipa_qmi_ctx->q6_ul_filter_rule, 0, sizeof(ipa_qmi_ctx->q6_ul_filter_rule)); - mutex_unlock(&add_mux_channel_lock); return -EINVAL; success: - mutex_unlock(&add_mux_channel_lock); return 0; } @@ -1627,12 +1622,9 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* already got Q6 UL filter rules*/ if (ipa_qmi_ctx && ipa_qmi_ctx->modem_cfg_emb_pipe_flt - == false) { - /* protect num_q6_rule */ - mutex_lock(&add_mux_channel_lock); + == false) rc = wwan_add_ul_flt_rule_to_ipa(); - mutex_unlock(&add_mux_channel_lock); - } else + else rc = 0; egress_set = true; if (rc) @@ -1886,9 +1878,7 @@ void q6_deinitialize_rm(void) if (ret < 0) IPAWANERR("Error deleting resource %d, ret=%d\n", IPA_RM_RESOURCE_Q6_PROD, ret); - - if (ipa_rm_q6_workqueue) - destroy_workqueue(ipa_rm_q6_workqueue); + destroy_workqueue(ipa_rm_q6_workqueue); } static void wake_tx_queue(struct work_struct *work) @@ -2197,10 +2187,7 @@ timer_init_err: IPAWANERR("Error deleting resource %d, ret=%d\n", IPA_RM_RESOURCE_WWAN_0_PROD, ret); create_rsrc_err: - - if (!atomic_read(&is_ssr)) - q6_deinitialize_rm(); - + q6_deinitialize_rm(); q6_init_err: free_netdev(ipa_netdevs[0]); ipa_netdevs[0] = NULL; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index c3a4ba2678937c7ac18b4084e410f0ebbf448a9c..a50cd0b807a2718713f95e874c7c3f737d35ec28 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -143,9 +143,6 @@ #define IPA_IOC_ALLOC_NAT_MEM32 _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ALLOC_NAT_MEM, \ compat_uptr_t) -#define IPA_IOC_ALLOC_NAT_TABLE32 _IOWR(IPA_IOC_MAGIC, \ - IPA_IOCTL_ALLOC_NAT_TABLE, \ - compat_uptr_t) #define IPA_IOC_V4_INIT_NAT32 _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_V4_INIT_NAT, \ compat_uptr_t) @@ -155,9 +152,6 @@ #define IPA_IOC_V4_DEL_NAT32 _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_V4_DEL_NAT, \ compat_uptr_t) -#define IPA_IOC_DEL_NAT_TABLE32 _IOWR(IPA_IOC_MAGIC, \ - IPA_IOCTL_DEL_NAT_TABLE, \ - compat_uptr_t) #define IPA_IOC_GET_NAT_OFFSET32 _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_GET_NAT_OFFSET, \ compat_uptr_t) @@ -213,18 +207,6 @@ struct ipa3_ioc_nat_alloc_mem32 { compat_size_t size; compat_off_t offset; }; - -/** -* struct ipa_ioc_nat_ipv6ct_table_alloc32 - table memory allocation -* properties -* @size: input parameter, size of table in bytes -* @offset: output parameter, offset into page in case of system memory -*/ -struct ipa_ioc_nat_ipv6ct_table_alloc32 { - compat_size_t size; - compat_off_t offset; -}; - #endif #define IPA_TZ_UNLOCK_ATTRIBUTE 0x0C0311 @@ -621,7 +603,7 @@ static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type) msg_meta.msg_len = sizeof(struct ipa_wan_msg); retval = ipa3_send_msg(&msg_meta, wan_msg, ipa3_wan_msg_free_cb); if (retval) { - IPAERR_RL("ipa3_send_msg failed: %d\n", retval); + IPAERR("ipa3_send_msg failed: %d\n", retval); kfree(wan_msg); return retval; } @@ -637,10 +619,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) u8 header[128] = { 0 }; u8 *param = NULL; struct ipa_ioc_nat_alloc_mem nat_mem; - struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc; struct ipa_ioc_v4_nat_init nat_init; struct ipa_ioc_v4_nat_del nat_del; - struct ipa_ioc_nat_ipv6ct_table_del table_del; struct ipa_ioc_rm_dependency rm_depend; size_t sz; int pre_entry; @@ -679,26 +659,6 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } break; - - case IPA_IOC_ALLOC_NAT_TABLE: - if (copy_from_user(&table_alloc, (const void __user *)arg, - sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc))) { - retval = -EFAULT; - break; - } - - if (ipa3_allocate_nat_table(&table_alloc)) { - retval = -EFAULT; - break; - } - if (table_alloc.offset && - copy_to_user((void __user *)arg, &table_alloc, sizeof( - struct ipa_ioc_nat_ipv6ct_table_alloc))) { - retval = -EFAULT; - break; - } - break; - case IPA_IOC_V4_INIT_NAT: if (copy_from_user((u8 *)&nat_init, (u8 *)arg, sizeof(struct ipa_ioc_v4_nat_init))) { @@ -735,7 +695,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_nat_dma_cmd *)param)->entries != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_nat_dma_cmd *)param)->entries, pre_entry); retval = -EFAULT; @@ -759,18 +719,6 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; - case IPA_IOC_DEL_NAT_TABLE: - if (copy_from_user(&table_del, (const void __user *)arg, - sizeof(struct ipa_ioc_nat_ipv6ct_table_del))) { - retval = -EFAULT; - break; - } - if (ipa3_del_nat_table(&table_del)) { - retval = -EFAULT; - break; - } - break; - case IPA_IOC_ADD_HDR: if (copy_from_user(header, (u8 *)arg, sizeof(struct ipa_ioc_add_hdr))) { @@ -794,7 +742,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_hdr *)param)->num_hdrs, pre_entry); retval = -EFAULT; @@ -833,7 +781,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_del_hdr *)param)->num_hdls, pre_entry); retval = -EFAULT; @@ -873,7 +821,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_rt_rule *)param)-> num_rules, pre_entry); @@ -913,7 +861,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_rt_rule_after *)param)-> num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_rt_rule_after *)param)-> num_rules, pre_entry); @@ -955,7 +903,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_mdfy_rt_rule *)param)->num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_mdfy_rt_rule *)param)-> num_rules, pre_entry); @@ -995,7 +943,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_del_rt_rule *)param)->num_hdls, pre_entry); retval = -EFAULT; @@ -1034,7 +982,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_flt_rule *)param)-> num_rules, pre_entry); @@ -1076,7 +1024,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_flt_rule_after *)param)-> num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_flt_rule_after *)param)-> num_rules, pre_entry); @@ -1117,7 +1065,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_del_flt_rule *)param)-> num_hdls, pre_entry); @@ -1157,7 +1105,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_mdfy_flt_rule *)param)->num_rules != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_mdfy_flt_rule *)param)-> num_rules, pre_entry); @@ -1295,7 +1243,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (unlikely(((struct ipa_ioc_query_intf_tx_props *) param)->num_tx_props != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_query_intf_tx_props *) param)->num_tx_props, pre_entry); retval = -EFAULT; @@ -1340,7 +1288,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_query_intf_rx_props *) param)->num_rx_props != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_query_intf_rx_props *) param)->num_rx_props, pre_entry); retval = -EFAULT; @@ -1385,7 +1333,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_query_intf_ext_props *) param)->num_ext_props != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_query_intf_ext_props *) param)->num_ext_props, pre_entry); retval = -EFAULT; @@ -1423,7 +1371,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_msg_meta *)param)->msg_len != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_msg_meta *)param)->msg_len, pre_entry); retval = -EFAULT; @@ -1563,7 +1511,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_add_hdr_proc_ctx *) param)->num_proc_ctxs != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_add_hdr_proc_ctx *) param)->num_proc_ctxs, pre_entry); retval = -EFAULT; @@ -1602,7 +1550,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* add check in case user-space module compromised */ if (unlikely(((struct ipa_ioc_del_hdr_proc_ctx *) param)->num_hdls != pre_entry)) { - IPAERR_RL("current %d pre %d\n", + IPAERR("current %d pre %d\n", ((struct ipa_ioc_del_hdr_proc_ctx *)param)-> num_hdls, pre_entry); @@ -1706,21 +1654,6 @@ int ipa3_setup_dflt_rt_tables(void) return 0; } -static int ipa3_clkon_cfg_wa(void) -{ - struct ipahal_reg_clkon_cfg clkon_cfg = { 0 }; - int ret = 0; - - clkon_cfg.cgc_open_misc = 1; - - if (ipa3_cfg_clkon_cfg(&clkon_cfg)) { - IPAERR("fail to set cgc_open_misc = 1\n"); - ret = -EPERM; - } - - return ret; -} - static int ipa3_setup_exception_path(void) { struct ipa_ioc_add_hdr *hdr; @@ -2300,6 +2233,7 @@ static int ipa3_q6_set_ex_path_to_apps(void) struct ipahal_imm_cmd_register_write reg_write; struct ipahal_imm_cmd_pyld *cmd_pyld; int retval; + struct ipahal_reg_valmask valmask; desc = kcalloc(ipa3_ctx->ipa_num_pipes, sizeof(struct ipa3_desc), GFP_KERNEL); @@ -2314,10 +2248,40 @@ static int ipa3_q6_set_ex_path_to_apps(void) if (ep_idx == -1) continue; - /* disable statuses for all modem controlled prod pipes */ - if (IPA_CLIENT_IS_Q6_PROD(client_idx) || - (ipa3_ctx->ep[ep_idx].valid && - ipa3_ctx->ep[ep_idx].skip_ep_cfg)) { + if (ipa3_ctx->ep[ep_idx].valid && + ipa3_ctx->ep[ep_idx].skip_ep_cfg) { + BUG_ON(num_descs >= ipa3_ctx->ipa_num_pipes); + + reg_write.skip_pipeline_clear = false; + reg_write.pipeline_clear_options = + IPAHAL_HPS_CLEAR; + reg_write.offset = + ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n, + ep_idx); + ipahal_get_status_ep_valmask( + ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS), + &valmask); + reg_write.value = valmask.val; + reg_write.value_mask = valmask.mask; + cmd_pyld = ipahal_construct_imm_cmd( + IPA_IMM_CMD_REGISTER_WRITE, ®_write, false); + if (!cmd_pyld) { + IPAERR("fail construct register_write cmd\n"); + BUG(); + } + + desc[num_descs].opcode = ipahal_imm_cmd_get_opcode( + IPA_IMM_CMD_REGISTER_WRITE); + desc[num_descs].type = IPA_IMM_CMD_DESC; + desc[num_descs].callback = ipa3_destroy_imm; + desc[num_descs].user1 = cmd_pyld; + desc[num_descs].pyld = cmd_pyld->data; + desc[num_descs].len = cmd_pyld->len; + num_descs++; + } + + /* disable statuses for modem producers */ + if (IPA_CLIENT_IS_Q6_PROD(client_idx)) { ipa_assert_on(num_descs >= ipa3_ctx->ipa_num_pipes); reg_write.skip_pipeline_clear = false; @@ -3049,34 +3013,6 @@ static void ipa3_teardown_apps_pipes(void) } #ifdef CONFIG_COMPAT -static long compat_ipa3_nat_ipv6ct_alloc_table(unsigned long arg, - int (alloc_func)(struct ipa_ioc_nat_ipv6ct_table_alloc *)) -{ - long retval; - struct ipa_ioc_nat_ipv6ct_table_alloc32 table_alloc32; - struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc; - - retval = copy_from_user(&table_alloc32, (const void __user *)arg, - sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32)); - if (retval) - return retval; - - table_alloc.size = (size_t)table_alloc32.size; - table_alloc.offset = (off_t)table_alloc32.offset; - - retval = alloc_func(&table_alloc); - if (retval) - return retval; - - if (table_alloc.offset) { - table_alloc32.offset = (compat_off_t)table_alloc.offset; - retval = copy_to_user((void __user *)arg, &table_alloc32, - sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32)); - } - - return retval; -} - long compat_ipa3_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int retval = 0; @@ -3148,9 +3084,6 @@ long compat_ipa3_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } ret: return retval; - case IPA_IOC_ALLOC_NAT_TABLE32: - return compat_ipa3_nat_ipv6ct_alloc_table(arg, - ipa3_allocate_nat_table); case IPA_IOC_V4_INIT_NAT32: cmd = IPA_IOC_V4_INIT_NAT; break; @@ -3160,9 +3093,6 @@ ret: case IPA_IOC_V4_DEL_NAT32: cmd = IPA_IOC_V4_DEL_NAT; break; - case IPA_IOC_DEL_NAT_TABLE32: - cmd = IPA_IOC_DEL_NAT_TABLE; - break; case IPA_IOC_GET_NAT_OFFSET32: cmd = IPA_IOC_GET_NAT_OFFSET; break; @@ -4032,8 +3962,6 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, /* Prevent consequent calls from trying to load the FW again. */ if (ipa3_ctx->ipa_initialization_complete) return 0; - /* move proxy vote for modem on ipa3_post_init */ - IPA_ACTIVE_CLIENTS_INC_SPECIAL("PROXY_CLK_VOTE"); if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) { memset(&gsi_props, 0, sizeof(gsi_props)); @@ -4135,14 +4063,8 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, ipa3_trigger_ipa_ready_cbs(); complete_all(&ipa3_ctx->init_completion_obj); + pr_info("IPA driver initialization was successful.\n"); - /* WA to disable MISC clock gating for IPA_HW_v3_1 */ - if (ipa3_ctx->ipa_hw_type == IPA_HW_v3_1) { - pr_info(" WA to set cgc_open_misc = 1\n"); - ipa3_clkon_cfg_wa(); - } - - pr_info("IPA driver initialization was successful\n"); return 0; fail_teth_bridge_driver_init: @@ -4353,6 +4275,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, int i; struct ipa3_flt_tbl *flt_tbl; struct ipa3_rt_tbl_set *rset; + struct ipa_active_client_logging_info log_info; IPADBG("IPA Driver initialization started\n"); @@ -4542,7 +4465,8 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, mutex_init(&ipa3_ctx->ipa3_active_clients.mutex); spin_lock_init(&ipa3_ctx->ipa3_active_clients.spinlock); - /* move proxy vote for modem to ipa3_post_init() */ + IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE"); + ipa3_active_clients_log_inc(&log_info, false); ipa3_ctx->ipa3_active_clients.cnt = 1; /* Assign resource limitation to each group */ @@ -4778,6 +4702,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, init_completion(&ipa3_ctx->init_completion_obj); init_completion(&ipa3_ctx->uc_loaded_completion_obj); + /* * For GSI, we can't register the GSI driver yet, as it expects * the GSI FW to be up and running before the registration. @@ -4820,8 +4745,6 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, IPADBG("ipa cdev added successful. major:%d minor:%d\n", MAJOR(ipa3_ctx->dev_num), MINOR(ipa3_ctx->dev_num)); - /* proxy vote for motem is added in ipa3_post_init() phase */ - IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return 0; fail_cdev_add: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 8c6bd48cfb2c601356f40446a4248b4e91122389..bc6622d4725b50688ef6b5572299a868d0009c70 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -1254,12 +1254,6 @@ int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params, memset(gsi_ep_cfg_ptr, 0, sizeof(struct ipa_gsi_ep_config)); gsi_ep_cfg_ptr = ipa_get_gsi_ep_info(ipa_ep_idx); - if (gsi_ep_cfg_ptr == NULL) { - IPAERR("Error ipa_get_gsi_ep_info ret NULL\n"); - result = -EFAULT; - goto write_evt_scratch_fail; - } - params->chan_params.evt_ring_hdl = ep->gsi_evt_ring_hdl; params->chan_params.ch_id = gsi_ep_cfg_ptr->ipa_gsi_chan_num; gsi_res = gsi_alloc_channel(¶ms->chan_params, gsi_dev_hdl, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index ce0bcfdef2f7540bbf8b75a5e73b14e5cb0a208f..fbf84ab7d2d47f9683f810fc14bf6a4c778ef38b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -863,11 +863,10 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count, eq = true; } else { rt_tbl = ipa3_id_find(entry->rule.rt_tbl_hdl); - if (rt_tbl == NULL || - rt_tbl->cookie != IPA_RT_TBL_COOKIE) - rt_tbl_idx = ~0; - else + if (rt_tbl) rt_tbl_idx = rt_tbl->idx; + else + rt_tbl_idx = ~0; bitmap = entry->rule.attrib.attrib_mask; eq = false; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 034b7fc45d8d91ae7a2bb51d7f46c6134ca5ee3b..6a3a89e2cf8daa2d9a1f4a087f4a3dddcd38f78c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1188,15 +1188,6 @@ static void ipa3_handle_rx(struct ipa3_sys_context *sys) } else { inactive_cycles = 0; } - - /* - * if pipe is out of buffers there is no point polling for - * completed descs; release the worker so delayed work can - * run in a timely manner - */ - if (sys->len == 0) - break; - } while (inactive_cycles <= POLLING_INACTIVITY_RX); trace_poll_to_intr3(sys->ep->client); @@ -2093,8 +2084,6 @@ static void ipa3_cleanup_wlan_rx_common_cache(void) struct ipa3_rx_pkt_wrapper *rx_pkt; struct ipa3_rx_pkt_wrapper *tmp; - spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); - list_for_each_entry_safe(rx_pkt, tmp, &ipa3_ctx->wc_memb.wlan_comm_desc_list, link) { list_del(&rx_pkt->link); @@ -2115,8 +2104,6 @@ static void ipa3_cleanup_wlan_rx_common_cache(void) IPAERR("wlan comm buff total cnt: %d\n", ipa3_ctx->wc_memb.wlan_comm_total_cnt); - spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); - } static void ipa3_alloc_wlan_rx_common_cache(u32 size) @@ -2154,13 +2141,11 @@ static void ipa3_alloc_wlan_rx_common_cache(u32 size) goto fail_dma_mapping; } - spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); list_add_tail(&rx_pkt->link, &ipa3_ctx->wc_memb.wlan_comm_desc_list); rx_len_cached = ++ipa3_ctx->wc_memb.wlan_comm_total_cnt; ipa3_ctx->wc_memb.wlan_comm_free_cnt++; - spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c index f5a1b2cc9758e43b4b6acc909aa96d68800a8c52..41b29335d23b3e66e7392ce589083076527e55dc 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c @@ -745,7 +745,7 @@ static int __ipa_validate_flt_rule(const struct ipa_flt_rule *rule, goto error; } - if ((*rt_tbl)->cookie != IPA_RT_TBL_COOKIE) { + if ((*rt_tbl)->cookie != IPA_COOKIE) { IPAERR("RT table cookie is invalid\n"); goto error; } @@ -787,7 +787,7 @@ static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry, } INIT_LIST_HEAD(&((*entry)->link)); (*entry)->rule = *rule; - (*entry)->cookie = IPA_FLT_COOKIE; + (*entry)->cookie = IPA_COOKIE; (*entry)->rt_tbl = rt_tbl; (*entry)->tbl = tbl; if (rule->rule_id) { @@ -822,18 +822,12 @@ static int __ipa_finish_flt_rule_add(struct ipa3_flt_tbl *tbl, if (id < 0) { IPAERR("failed to add to tree\n"); WARN_ON(1); - goto ipa_insert_failed; } *rule_hdl = id; entry->id = id; IPADBG_LOW("add flt rule rule_cnt=%d\n", tbl->rule_cnt); return 0; -ipa_insert_failed: - if (entry->rt_tbl) - entry->rt_tbl->ref_cnt--; - tbl->rule_cnt--; - return -EPERM; } static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, @@ -859,16 +853,9 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, list_add(&entry->link, &tbl->head_flt_rule_list); } - if (__ipa_finish_flt_rule_add(tbl, entry, rule_hdl)) - goto ipa_insert_failed; + __ipa_finish_flt_rule_add(tbl, entry, rule_hdl); return 0; -ipa_insert_failed: - list_del(&entry->link); - /* if rule id was allocated from idr, remove it */ - if (!(entry->rule_id & ipahal_get_rule_id_hi_bit())) - idr_remove(&entry->tbl->rule_ids, entry->rule_id); - kmem_cache_free(ipa3_ctx->flt_rule_cache, entry); error: return -EPERM; @@ -887,7 +874,7 @@ static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl, goto error; if (rule == NULL || rule_hdl == NULL) { - IPAERR_RL("bad parms rule=%p rule_hdl=%p\n", rule, + IPAERR("bad parms rule=%p rule_hdl=%p\n", rule, rule_hdl); goto error; } @@ -900,8 +887,7 @@ static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl, list_add(&entry->link, &((*add_after_entry)->link)); - if (__ipa_finish_flt_rule_add(tbl, entry, rule_hdl)) - goto ipa_insert_failed; + __ipa_finish_flt_rule_add(tbl, entry, rule_hdl); /* * prepare for next insertion @@ -910,13 +896,6 @@ static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl, return 0; -ipa_insert_failed: - list_del(&entry->link); - /* if rule id was allocated from idr, remove it */ - if (!(entry->rule_id & ipahal_get_rule_id_hi_bit())) - idr_remove(&entry->tbl->rule_ids, entry->rule_id); - kmem_cache_free(ipa3_ctx->flt_rule_cache, entry); - error: *add_after_entry = NULL; return -EPERM; @@ -929,12 +908,12 @@ static int __ipa_del_flt_rule(u32 rule_hdl) entry = ipa3_id_find(rule_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); return -EINVAL; } - if (entry->cookie != IPA_FLT_COOKIE) { - IPAERR_RL("bad params\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad params\n"); return -EINVAL; } id = entry->id; @@ -966,12 +945,12 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule, entry = ipa3_id_find(frule->rule_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); goto error; } - if (entry->cookie != IPA_FLT_COOKIE) { - IPAERR_RL("bad params\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad params\n"); goto error; } @@ -981,25 +960,25 @@ static int __ipa_mdfy_flt_rule(struct ipa_flt_rule_mdfy *frule, if (frule->rule.action != IPA_PASS_TO_EXCEPTION) { if (!frule->rule.eq_attrib_type) { if (!frule->rule.rt_tbl_hdl) { - IPAERR_RL("invalid RT tbl\n"); + IPAERR("invalid RT tbl\n"); goto error; } rt_tbl = ipa3_id_find(frule->rule.rt_tbl_hdl); if (rt_tbl == NULL) { - IPAERR_RL("RT tbl not found\n"); + IPAERR("RT tbl not found\n"); goto error; } - if (rt_tbl->cookie != IPA_RT_TBL_COOKIE) { - IPAERR_RL("RT table cookie is invalid\n"); + if (rt_tbl->cookie != IPA_COOKIE) { + IPAERR("RT table cookie is invalid\n"); goto error; } } else { if (frule->rule.rt_tbl_idx > ((ip == IPA_IP_v4) ? IPA_MEM_PART(v4_modem_rt_index_hi) : IPA_MEM_PART(v6_modem_rt_index_hi))) { - IPAERR_RL("invalid RT tbl\n"); + IPAERR("invalid RT tbl\n"); goto error; } } @@ -1044,7 +1023,7 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, int ipa_ep_idx; if (rule == NULL || rule_hdl == NULL || ep >= IPA_CLIENT_MAX) { - IPAERR_RL("bad parms rule=%p rule_hdl=%p ep=%d\n", rule, + IPAERR("bad parms rule=%p rule_hdl=%p ep=%d\n", rule, rule_hdl, ep); return -EINVAL; @@ -1074,7 +1053,7 @@ int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1089,7 +1068,7 @@ int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) result = -1; if (result) { - IPAERR_RL("failed to add flt rule %d\n", i); + IPAERR("failed to add flt rule %d\n", i); rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; @@ -1097,7 +1076,7 @@ int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) } if (rules->global) { - IPAERR_RL("no support for global filter rules\n"); + IPAERR("no support for global filter rules\n"); result = -EPERM; goto bail; } @@ -1132,12 +1111,12 @@ int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules) if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } if (rules->ep >= IPA_CLIENT_MAX) { - IPAERR_RL("bad parms ep=%d\n", rules->ep); + IPAERR("bad parms ep=%d\n", rules->ep); return -EINVAL; } @@ -1152,27 +1131,20 @@ int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules) entry = ipa3_id_find(rules->add_after_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); - result = -EINVAL; - goto bail; - } - - if (entry->cookie != IPA_FLT_COOKIE) { - IPAERR_RL("Invalid cookie value = %u rule = %d in rt tbls\n", - entry->cookie, rules->add_after_hdl); + IPAERR("lookup failed\n"); result = -EINVAL; goto bail; } if (entry->tbl != tbl) { - IPAERR_RL("given entry does not match the table\n"); + IPAERR("given entry does not match the table\n"); result = -EINVAL; goto bail; } if (tbl->sticky_rear) if (&entry->link == tbl->head_flt_rule_list.prev) { - IPAERR_RL("cannot add rule at end of a sticky table"); + IPAERR("cannot add rule at end of a sticky table"); result = -EINVAL; goto bail; } @@ -1194,7 +1166,7 @@ int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules) &entry); if (result) { - IPAERR_RL("failed to add flt rule %d\n", i); + IPAERR("failed to add flt rule %d\n", i); rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; @@ -1228,14 +1200,14 @@ int ipa3_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls) int result; if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); for (i = 0; i < hdls->num_hdls; i++) { if (__ipa_del_flt_rule(hdls->hdl[i].hdl)) { - IPAERR_RL("failed to del flt rule %i\n", i); + IPAERR("failed to del flt rule %i\n", i); hdls->hdl[i].status = IPA_FLT_STATUS_OF_DEL_FAILED; } else { hdls->hdl[i].status = 0; @@ -1268,14 +1240,14 @@ int ipa3_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *hdls) int result; if (hdls == NULL || hdls->num_rules == 0 || hdls->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); for (i = 0; i < hdls->num_rules; i++) { if (__ipa_mdfy_flt_rule(&hdls->rules[i], hdls->ip)) { - IPAERR_RL("failed to mdfy flt rule %i\n", i); + IPAERR("failed to mdfy flt rule %i\n", i); hdls->rules[i].status = IPA_FLT_STATUS_OF_MDFY_FAILED; } else { hdls->rules[i].status = 0; @@ -1309,7 +1281,7 @@ int ipa3_commit_flt(enum ipa_ip_type ip) int result; if (ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1345,7 +1317,7 @@ int ipa3_reset_flt(enum ipa_ip_type ip) int id; if (ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index ce35ba02154df3b9bdc7de1afa99899314cd8dfd..a5186f1aff358f9d22f0711917e0102c3d6ece2b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -330,17 +330,17 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, proc_ctx->type, proc_ctx->hdr_hdl); if (!HDR_PROC_TYPE_IS_VALID(proc_ctx->type)) { - IPAERR_RL("invalid processing type %d\n", proc_ctx->type); + IPAERR("invalid processing type %d\n", proc_ctx->type); return -EINVAL; } hdr_entry = ipa3_id_find(proc_ctx->hdr_hdl); if (!hdr_entry) { - IPAERR_RL("hdr_hdl is invalid\n"); + IPAERR("hdr_hdl is invalid\n"); return -EINVAL; } - if (hdr_entry->cookie != IPA_HDR_COOKIE) { - IPAERR_RL("Invalid header cookie %u\n", hdr_entry->cookie); + if (hdr_entry->cookie != IPA_COOKIE) { + IPAERR("Invalid header cookie %u\n", hdr_entry->cookie); WARN_ON(1); return -EINVAL; } @@ -359,7 +359,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, entry->hdr = hdr_entry; if (add_ref_hdr) hdr_entry->ref_cnt++; - entry->cookie = IPA_PROC_HDR_COOKIE; + entry->cookie = IPA_COOKIE; needed_len = ipahal_get_proc_ctx_needed_len(proc_ctx->type); @@ -369,7 +369,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN1]) { bin = IPA_HDR_PROC_CTX_BIN1; } else { - IPAERR_RL("unexpected needed len %d\n", needed_len); + IPAERR("unexpected needed len %d\n", needed_len); WARN_ON(1); goto bad_len; } @@ -379,7 +379,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr); if (list_empty(&htbl->head_free_offset_list[bin])) { if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) { - IPAERR_RL("hdr proc ctx table overflow\n"); + IPAERR("hdr proc ctx table overflow\n"); goto bad_len; } @@ -417,7 +417,6 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, if (id < 0) { IPAERR("failed to alloc id\n"); WARN_ON(1); - goto ipa_insert_failed; } entry->id = id; proc_ctx->proc_ctx_hdl = id; @@ -425,13 +424,6 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, return 0; -ipa_insert_failed: - list_move(&offset->link, - &htbl->head_free_offset_list[offset->bin]); - entry->offset_entry = NULL; - list_del(&entry->link); - htbl->proc_ctx_cnt--; - bad_len: if (add_ref_hdr) hdr_entry->ref_cnt--; @@ -444,19 +436,19 @@ bad_len: static int __ipa_add_hdr(struct ipa_hdr_add *hdr) { struct ipa3_hdr_entry *entry; - struct ipa_hdr_offset_entry *offset = NULL; + struct ipa_hdr_offset_entry *offset; u32 bin; struct ipa3_hdr_tbl *htbl = &ipa3_ctx->hdr_tbl; int id; int mem_size; if (hdr->hdr_len == 0 || hdr->hdr_len > IPA_HDR_MAX_SIZE) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); goto error; } if (!HDR_TYPE_IS_VALID(hdr->type)) { - IPAERR_RL("invalid hdr type %d\n", hdr->type); + IPAERR("invalid hdr type %d\n", hdr->type); goto error; } @@ -475,7 +467,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) entry->type = hdr->type; entry->is_eth2_ofst_valid = hdr->is_eth2_ofst_valid; entry->eth2_ofst = hdr->eth2_ofst; - entry->cookie = IPA_HDR_COOKIE; + entry->cookie = IPA_COOKIE; if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN0]) bin = IPA_HDR_BIN0; @@ -488,7 +480,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) else if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN4]) bin = IPA_HDR_BIN4; else { - IPAERR_RL("unexpected hdr len %d\n", hdr->hdr_len); + IPAERR("unexpected hdr len %d\n", hdr->hdr_len); goto bad_hdr_len; } @@ -554,7 +546,6 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) if (id < 0) { IPAERR("failed to alloc id\n"); WARN_ON(1); - goto ipa_insert_failed; } entry->id = id; hdr->hdr_hdl = id; @@ -579,19 +570,10 @@ fail_add_proc_ctx: entry->ref_cnt--; hdr->hdr_hdl = 0; ipa3_id_remove(id); -ipa_insert_failed: - if (entry->is_hdr_proc_ctx) { - dma_unmap_single(ipa3_ctx->pdev, entry->phys_base, - entry->hdr_len, DMA_TO_DEVICE); - } else { - if (offset) - list_move(&offset->link, - &htbl->head_free_offset_list[offset->bin]); - entry->offset_entry = NULL; - } htbl->hdr_cnt--; list_del(&entry->link); - + dma_unmap_single(ipa3_ctx->pdev, entry->phys_base, + entry->hdr_len, DMA_TO_DEVICE); fail_dma_mapping: entry->is_hdr_proc_ctx = false; @@ -609,8 +591,8 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, struct ipa3_hdr_proc_ctx_tbl *htbl = &ipa3_ctx->hdr_proc_ctx_tbl; entry = ipa3_id_find(proc_ctx_hdl); - if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) { - IPAERR_RL("bad parm\n"); + if (!entry || (entry->cookie != IPA_COOKIE)) { + IPAERR("bad parm\n"); return -EINVAL; } @@ -618,7 +600,7 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, htbl->proc_ctx_cnt, entry->offset_entry->offset); if (by_user && entry->user_deleted) { - IPAERR_RL("proc_ctx already deleted by user\n"); + IPAERR("proc_ctx already deleted by user\n"); return -EINVAL; } @@ -656,12 +638,12 @@ int __ipa3_del_hdr(u32 hdr_hdl, bool by_user) entry = ipa3_id_find(hdr_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); return -EINVAL; } - if (entry->cookie != IPA_HDR_COOKIE) { - IPAERR_RL("bad parm\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad parm\n"); return -EINVAL; } @@ -674,7 +656,7 @@ int __ipa3_del_hdr(u32 hdr_hdl, bool by_user) entry->offset_entry->offset); if (by_user && entry->user_deleted) { - IPAERR_RL("proc_ctx already deleted by user\n"); + IPAERR("proc_ctx already deleted by user\n"); return -EINVAL; } @@ -723,7 +705,7 @@ int ipa3_add_hdr(struct ipa_ioc_add_hdr *hdrs) int result = -EFAULT; if (hdrs == NULL || hdrs->num_hdrs == 0) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -732,7 +714,7 @@ int ipa3_add_hdr(struct ipa_ioc_add_hdr *hdrs) hdrs->num_hdrs); for (i = 0; i < hdrs->num_hdrs; i++) { if (__ipa_add_hdr(&hdrs->hdr[i])) { - IPAERR_RL("failed to add hdr %d\n", i); + IPAERR("failed to add hdr %d\n", i); hdrs->hdr[i].status = -1; } else { hdrs->hdr[i].status = 0; @@ -768,14 +750,14 @@ int ipa3_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user) int result = -EFAULT; if (hdls == NULL || hdls->num_hdls == 0) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); for (i = 0; i < hdls->num_hdls; i++) { if (__ipa3_del_hdr(hdls->hdl[i].hdl, by_user)) { - IPAERR_RL("failed to del hdr %i\n", i); + IPAERR("failed to del hdr %i\n", i); hdls->hdl[i].status = -1; } else { hdls->hdl[i].status = 0; @@ -823,7 +805,7 @@ int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) int result = -EFAULT; if (proc_ctxs == NULL || proc_ctxs->num_proc_ctxs == 0) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -832,7 +814,7 @@ int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) proc_ctxs->num_proc_ctxs); for (i = 0; i < proc_ctxs->num_proc_ctxs; i++) { if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], true)) { - IPAERR_RL("failed to add hdr pric ctx %d\n", i); + IPAERR("failed to add hdr pric ctx %d\n", i); proc_ctxs->proc_ctx[i].status = -1; } else { proc_ctxs->proc_ctx[i].status = 0; @@ -870,14 +852,14 @@ int ipa3_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls, int result; if (hdls == NULL || hdls->num_hdls == 0) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); for (i = 0; i < hdls->num_hdls; i++) { if (__ipa3_del_hdr_proc_ctx(hdls->hdl[i].hdl, true, by_user)) { - IPAERR_RL("failed to del hdr %i\n", i); + IPAERR("failed to del hdr %i\n", i); hdls->hdl[i].status = -1; } else { hdls->hdl[i].status = 0; @@ -1084,7 +1066,7 @@ static struct ipa3_hdr_entry *__ipa_find_hdr(const char *name) struct ipa3_hdr_entry *entry; if (strnlen(name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) { - IPAERR_RL("Header name too long: %s\n", name); + IPAERR("Header name too long: %s\n", name); return NULL; } @@ -1114,7 +1096,7 @@ int ipa3_get_hdr(struct ipa_ioc_get_hdr *lookup) int result = -1; if (lookup == NULL) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); @@ -1201,13 +1183,13 @@ int ipa3_put_hdr(u32 hdr_hdl) entry = ipa3_id_find(hdr_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); result = -EINVAL; goto bail; } - if (entry->cookie != IPA_HDR_COOKIE) { - IPAERR_RL("invalid header entry\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("invalid header entry\n"); result = -EINVAL; goto bail; } @@ -1235,7 +1217,7 @@ int ipa3_copy_hdr(struct ipa_ioc_copy_hdr *copy) int result = -EFAULT; if (copy == NULL) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 9e57f54d719c5758131ba37b62dc96b93a9dbff4..ac7ef6a219523b1b512c8a2aa717c9413ed8a680 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -38,13 +38,8 @@ #include "ipa_uc_offload_i.h" #define DRV_NAME "ipa" +#define NAT_DEV_NAME "ipaNatTable" #define IPA_COOKIE 0x57831603 -#define IPA_RT_RULE_COOKIE 0x57831604 -#define IPA_RT_TBL_COOKIE 0x57831605 -#define IPA_FLT_COOKIE 0x57831606 -#define IPA_HDR_COOKIE 0x57831607 -#define IPA_PROC_HDR_COOKIE 0x57831608 - #define MTU_BYTE 1500 #define IPA_EP_NOT_ALLOCATED (-1) @@ -94,18 +89,6 @@ } \ } while (0) -#define IPAERR_RL(fmt, args...) \ - do { \ - pr_err_ratelimited(DRV_NAME " %s:%d " fmt, __func__,\ - __LINE__, ## args);\ - if (ipa3_ctx) { \ - IPA_IPC_LOGGING(ipa3_ctx->logbuf, \ - DRV_NAME " %s:%d " fmt, ## args); \ - IPA_IPC_LOGGING(ipa3_ctx->logbuf_low, \ - DRV_NAME " %s:%d " fmt, ## args); \ - } \ - } while (0) - #define WLAN_AMPDU_TX_EP 15 #define WLAN_PROD_TX_EP 19 #define WLAN1_CONS_RX_EP 14 @@ -234,8 +217,8 @@ struct ipa_smmu_cb_ctx { */ struct ipa3_flt_entry { struct list_head link; - u32 cookie; struct ipa_flt_rule rule; + u32 cookie; struct ipa3_flt_tbl *tbl; struct ipa3_rt_tbl *rt_tbl; u32 hw_len; @@ -263,13 +246,13 @@ struct ipa3_flt_entry { */ struct ipa3_rt_tbl { struct list_head link; - u32 cookie; struct list_head head_rt_rule_list; char name[IPA_RESOURCE_NAME_MAX]; u32 idx; u32 rule_cnt; u32 ref_cnt; struct ipa3_rt_tbl_set *set; + u32 cookie; bool in_sys[IPA_RULE_TYPE_MAX]; u32 sz[IPA_RULE_TYPE_MAX]; struct ipa_mem_buffer curr_mem[IPA_RULE_TYPE_MAX]; @@ -301,7 +284,6 @@ struct ipa3_rt_tbl { */ struct ipa3_hdr_entry { struct list_head link; - u32 cookie; u8 hdr[IPA_HDR_MAX_SIZE]; u32 hdr_len; char name[IPA_RESOURCE_NAME_MAX]; @@ -311,6 +293,7 @@ struct ipa3_hdr_entry { dma_addr_t phys_base; struct ipa3_hdr_proc_ctx_entry *proc_ctx; struct ipa_hdr_offset_entry *offset_entry; + u32 cookie; u32 ref_cnt; int id; u8 is_eth2_ofst_valid; @@ -359,10 +342,10 @@ struct ipa3_hdr_proc_ctx_offset_entry { */ struct ipa3_hdr_proc_ctx_entry { struct list_head link; - u32 cookie; enum ipa_hdr_proc_type type; struct ipa3_hdr_proc_ctx_offset_entry *offset_entry; struct ipa3_hdr_entry *hdr; + u32 cookie; u32 ref_cnt; int id; bool user_deleted; @@ -424,8 +407,8 @@ struct ipa3_flt_tbl { */ struct ipa3_rt_entry { struct list_head link; - u32 cookie; struct ipa_rt_rule rule; + u32 cookie; struct ipa3_rt_tbl *tbl; struct ipa3_hdr_entry *hdr; struct ipa3_hdr_proc_ctx_entry *proc_ctx; @@ -1639,15 +1622,12 @@ int ipa3_reset_flt(enum ipa_ip_type ip); * NAT */ int ipa3_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem); -int ipa3_allocate_nat_table( - struct ipa_ioc_nat_ipv6ct_table_alloc *table_alloc); int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init); int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma); int ipa3_nat_del_cmd(struct ipa_ioc_v4_nat_del *del); -int ipa3_del_nat_table(struct ipa_ioc_nat_ipv6ct_table_del *del); /* * Messaging @@ -1879,7 +1859,6 @@ void ipa3_dump_buff_internal(void *base, dma_addr_t phy_base, u32 size); #else #define IPA_DUMP_BUFF(base, phy_base, size) #endif -int ipa3_cfg_clkon_cfg(struct ipahal_reg_clkon_cfg *clkon_cfg); int ipa3_init_mem_partition(struct device_node *dev_node); int ipa3_controller_static_bind(struct ipa3_controller *controller, enum ipa_hw_type ipa_hw_type); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c index 76f37162f49527635cba6107f65e648e5576895e..38e8d4e9d63934753e126caadd5b43c0ce17ecde 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c @@ -227,7 +227,7 @@ int ipa3_query_intf(struct ipa_ioc_query_intf *lookup) if (strnlen(lookup->name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) { - IPAERR_RL("Interface name too long. (%s)\n", lookup->name); + IPAERR("Interface name too long. (%s)\n", lookup->name); return result; } @@ -268,7 +268,7 @@ int ipa3_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx) } if (strnlen(tx->name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) { - IPAERR_RL("Interface name too long. (%s)\n", tx->name); + IPAERR("Interface name too long. (%s)\n", tx->name); return result; } @@ -277,7 +277,7 @@ int ipa3_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx) if (!strcmp(entry->name, tx->name)) { /* add the entry check */ if (entry->num_tx_props != tx->num_tx_props) { - IPAERR_RL("invalid entry number(%u %u)\n", + IPAERR("invalid entry number(%u %u)\n", entry->num_tx_props, tx->num_tx_props); mutex_unlock(&ipa3_ctx->lock); @@ -315,7 +315,7 @@ int ipa3_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx) } if (strnlen(rx->name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) { - IPAERR_RL("Interface name too long. (%s)\n", rx->name); + IPAERR("Interface name too long. (%s)\n", rx->name); return result; } @@ -324,7 +324,7 @@ int ipa3_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx) if (!strcmp(entry->name, rx->name)) { /* add the entry check */ if (entry->num_rx_props != rx->num_rx_props) { - IPAERR_RL("invalid entry number(%u %u)\n", + IPAERR("invalid entry number(%u %u)\n", entry->num_rx_props, rx->num_rx_props); mutex_unlock(&ipa3_ctx->lock); @@ -366,7 +366,7 @@ int ipa3_query_intf_ext_props(struct ipa_ioc_query_intf_ext_props *ext) if (!strcmp(entry->name, ext->name)) { /* add the entry check */ if (entry->num_ext_props != ext->num_ext_props) { - IPAERR_RL("invalid entry number(%u %u)\n", + IPAERR("invalid entry number(%u %u)\n", entry->num_ext_props, ext->num_ext_props); mutex_unlock(&ipa3_ctx->lock); @@ -410,13 +410,13 @@ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff, if (meta == NULL || (buff == NULL && callback != NULL) || (buff != NULL && callback == NULL)) { - IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n", + IPAERR("invalid param meta=%p buff=%p, callback=%p\n", meta, buff, callback); return -EINVAL; } if (meta->msg_type >= IPA_EVENT_MAX_NUM) { - IPAERR_RL("unsupported message type %d\n", meta->msg_type); + IPAERR("unsupported message type %d\n", meta->msg_type); return -EINVAL; } @@ -640,7 +640,7 @@ int ipa3_pull_msg(struct ipa_msg_meta *meta, char *buff, size_t count) int result = -EINVAL; if (meta == NULL || buff == NULL || !count) { - IPAERR_RL("invalid param name=%p buff=%p count=%zu\n", + IPAERR("invalid param name=%p buff=%p count=%zu\n", meta, buff, count); return result; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 0bf2be7f8463b63ab3de6580070a7666f7e90330..cd027c28e597662d6c878f554d34d1c493f1d826 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -191,7 +191,7 @@ static int ipa3_mhi_get_ch_poll_cfg(enum ipa_client_type client, static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, int ipa_ep_idx, struct start_gsi_channel *params) { - int res = 0; + int res; struct gsi_evt_ring_props ev_props; struct ipa_mhi_msi_info *msi; struct gsi_chan_props ch_props; @@ -241,6 +241,7 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, if (res) { IPA_MHI_ERR("gsi_alloc_evt_ring failed %d\n", res); goto fail_alloc_evt; + return res; } IPA_MHI_DBG("client %d, caching event ring hdl %lu\n", client, @@ -258,6 +259,7 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, IPA_MHI_ERR("event ring wp is not updated. base=wp=0x%llx\n", params->ev_ctx_host->wp); goto fail_alloc_ch; + return res; } IPA_MHI_DBG("Ring event db: evt_ring_hdl=%lu host_wp=0x%llx\n", @@ -268,6 +270,7 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, IPA_MHI_ERR("fail to ring evt ring db %d. hdl=%lu wp=0x%llx\n", res, ep->gsi_evt_ring_hdl, params->ev_ctx_host->wp); goto fail_alloc_ch; + return res; } memset(&ch_props, 0, sizeof(ch_props)); @@ -630,8 +633,6 @@ int ipa3_mhi_destroy_channel(enum ipa_client_type client) } ep = &ipa3_ctx->ep[ipa_ep_idx]; - IPA_ACTIVE_CLIENTS_INC_EP(client); - IPA_MHI_DBG("reset event ring (hdl: %lu, ep: %d)\n", ep->gsi_evt_ring_hdl, ipa_ep_idx); @@ -653,10 +654,8 @@ int ipa3_mhi_destroy_channel(enum ipa_client_type client) goto fail; } - IPA_ACTIVE_CLIENTS_DEC_EP(client); return 0; fail: - IPA_ACTIVE_CLIENTS_DEC_EP(client); return res; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c index a78a0a608cb4e3eb82c0f24916a44c97557fd800..e7e5cf114242e35195d4ae74cf6cb9e23d3b02fd 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -34,6 +34,7 @@ enum nat_table_type { #define NAT_TABLE_ENTRY_SIZE_BYTE 32 #define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4 + static int ipa3_nat_vma_fault_remap( struct vm_area_struct *vma, struct vm_fault *vmf) { @@ -166,7 +167,7 @@ int ipa3_create_nat_device(void) IPADBG("\n"); mutex_lock(&nat_ctx->lock); - nat_ctx->class = class_create(THIS_MODULE, IPA_NAT_DEV_NAME); + nat_ctx->class = class_create(THIS_MODULE, NAT_DEV_NAME); if (IS_ERR(nat_ctx->class)) { IPAERR("unable to create the class\n"); result = -ENODEV; @@ -175,7 +176,7 @@ int ipa3_create_nat_device(void) result = alloc_chrdev_region(&nat_ctx->dev_num, 0, 1, - IPA_NAT_DEV_NAME); + NAT_DEV_NAME); if (result) { IPAERR("alloc_chrdev_region err.\n"); result = -ENODEV; @@ -184,7 +185,7 @@ int ipa3_create_nat_device(void) nat_ctx->dev = device_create(nat_ctx->class, NULL, nat_ctx->dev_num, nat_ctx, - "%s", IPA_NAT_DEV_NAME); + "%s", NAT_DEV_NAME); if (IS_ERR(nat_ctx->dev)) { IPAERR("device_create err:%ld\n", PTR_ERR(nat_ctx->dev)); @@ -252,10 +253,9 @@ int ipa3_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem) IPADBG("passed memory size %zu\n", mem->size); mutex_lock(&nat_ctx->lock); - if (strcmp(IPA_NAT_DEV_NAME, mem->dev_name)) { - IPAERR_RL("Nat device name mismatch\n"); - IPAERR_RL("Expect: %s Recv: %s\n", - IPA_NAT_DEV_NAME, mem->dev_name); + if (strcmp(mem->dev_name, NAT_DEV_NAME)) { + IPAERR("Nat device name mismatch\n"); + IPAERR("Expect: %s Recv: %s\n", NAT_DEV_NAME, mem->dev_name); result = -EPERM; goto bail; } @@ -274,7 +274,7 @@ int ipa3_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem) if (mem->size <= 0 || nat_ctx->is_dev_init == true) { - IPAERR_RL("Invalid Parameters or device is already init\n"); + IPAERR("Invalid Parameters or device is already init\n"); result = -EPERM; goto bail; } @@ -306,34 +306,6 @@ bail: return result; } -/** -* ipa3_allocate_nat_table() - Allocates memory for the NAT table -* @table_alloc: [in/out] memory parameters -* -* Called by NAT client to allocate memory for the table entries. -* Based on the request size either shared or system memory will be used. -* -* Returns: 0 on success, negative on failure -*/ -int ipa3_allocate_nat_table(struct ipa_ioc_nat_ipv6ct_table_alloc *table_alloc) -{ - int result; - struct ipa_ioc_nat_alloc_mem tmp; - - strlcpy(tmp.dev_name, IPA_NAT_DEV_NAME, IPA_RESOURCE_NAME_MAX); - tmp.size = table_alloc->size; - tmp.offset = 0; - - result = ipa3_allocate_nat_device(&tmp); - if (result) - goto bail; - - table_alloc->offset = tmp.offset; - -bail: - return result; -} - /* IOCTL function handlers */ /** * ipa3_nat_init_cmd() - Post IP_V4_NAT_INIT command to IPA HW @@ -365,16 +337,16 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) /* check for integer overflow */ if (init->ipv4_rules_offset > UINT_MAX - (TBL_ENTRY_SIZE * (init->table_entries + 1))) { - IPAERR_RL("Detected overflow\n"); - return -EPERM; + IPAERR("Detected overflow\n"); + return -EPERM; } /* Check Table Entry offset is not beyond allocated size */ tmp = init->ipv4_rules_offset + (TBL_ENTRY_SIZE * (init->table_entries + 1)); if (tmp > ipa3_ctx->nat_mem.size) { - IPAERR_RL("Table rules offset not valid\n"); - IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", + IPAERR("Table rules offset not valid\n"); + IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->ipv4_rules_offset, (init->table_entries + 1), tmp, ipa3_ctx->nat_mem.size); return -EPERM; @@ -382,17 +354,17 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) /* check for integer overflow */ if (init->expn_rules_offset > - (UINT_MAX - (TBL_ENTRY_SIZE * init->expn_table_entries))) { - IPAERR_RL("Detected overflow\n"); - return -EPERM; + UINT_MAX - (TBL_ENTRY_SIZE * init->expn_table_entries)) { + IPAERR("Detected overflow\n"); + return -EPERM; } /* Check Expn Table Entry offset is not beyond allocated size */ tmp = init->expn_rules_offset + (TBL_ENTRY_SIZE * init->expn_table_entries); if (tmp > ipa3_ctx->nat_mem.size) { - IPAERR_RL("Expn Table rules offset not valid\n"); - IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", + IPAERR("Expn Table rules offset not valid\n"); + IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->expn_rules_offset, init->expn_table_entries, tmp, ipa3_ctx->nat_mem.size); return -EPERM; @@ -401,16 +373,16 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) /* check for integer overflow */ if (init->index_offset > UINT_MAX - (INDX_TBL_ENTRY_SIZE * (init->table_entries + 1))) { - IPAERR_RL("Detected overflow\n"); - return -EPERM; + IPAERR("Detected overflow\n"); + return -EPERM; } /* Check Indx Table Entry offset is not beyond allocated size */ tmp = init->index_offset + (INDX_TBL_ENTRY_SIZE * (init->table_entries + 1)); if (tmp > ipa3_ctx->nat_mem.size) { - IPAERR_RL("Indx Table rules offset not valid\n"); - IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", + IPAERR("Indx Table rules offset not valid\n"); + IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->index_offset, (init->table_entries + 1), tmp, ipa3_ctx->nat_mem.size); return -EPERM; @@ -419,16 +391,16 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) /* check for integer overflow */ if (init->index_expn_offset > UINT_MAX - (INDX_TBL_ENTRY_SIZE * init->expn_table_entries)) { - IPAERR_RL("Detected overflow\n"); - return -EPERM; + IPAERR("Detected overflow\n"); + return -EPERM; } /* Check Expn Table entry offset is not beyond allocated size */ tmp = init->index_expn_offset + (INDX_TBL_ENTRY_SIZE * init->expn_table_entries); if (tmp > ipa3_ctx->nat_mem.size) { - IPAERR_RL("Indx Expn Table rules offset not valid\n"); - IPAERR_RL("offset:%d entrys:%d size:%zu mem_size:%zu\n", + IPAERR("Indx Expn Table rules offset not valid\n"); + IPAERR("offset:%d entrys:%d size:%zu mem_size:%zu\n", init->index_expn_offset, init->expn_table_entries, tmp, ipa3_ctx->nat_mem.size); return -EPERM; @@ -465,16 +437,16 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) (init->expn_rules_offset > offset) || (init->index_offset > offset) || (init->index_expn_offset > offset)) { - IPAERR_RL("Failed due to integer overflow\n"); - IPAERR_RL("nat.mem.dma_handle: 0x%pa\n", + IPAERR("Failed due to integer overflow\n"); + IPAERR("nat.mem.dma_handle: 0x%pa\n", &ipa3_ctx->nat_mem.dma_handle); - IPAERR_RL("ipv4_rules_offset: 0x%x\n", + IPAERR("ipv4_rules_offset: 0x%x\n", init->ipv4_rules_offset); - IPAERR_RL("expn_rules_offset: 0x%x\n", + IPAERR("expn_rules_offset: 0x%x\n", init->expn_rules_offset); - IPAERR_RL("index_offset: 0x%x\n", + IPAERR("index_offset: 0x%x\n", init->index_offset); - IPAERR_RL("index_expn_offset: 0x%x\n", + IPAERR("index_expn_offset: 0x%x\n", init->index_expn_offset); result = -EPERM; goto free_nop; @@ -524,7 +496,7 @@ int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init) cmd_pyld = ipahal_construct_imm_cmd( IPA_IMM_CMD_IP_V4_NAT_INIT, &cmd, false); if (!cmd_pyld) { - IPAERR_RL("Fail to construct ip_v4_nat_init imm cmd\n"); + IPAERR("Fail to construct ip_v4_nat_init imm cmd\n"); result = -EPERM; goto free_nop; } @@ -604,7 +576,7 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) IPADBG("\n"); if (dma->entries <= 0) { - IPAERR_RL("Invalid number of commands %d\n", + IPAERR("Invalid number of commands %d\n", dma->entries); ret = -EPERM; goto bail; @@ -612,7 +584,7 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) for (cnt = 0; cnt < dma->entries; cnt++) { if (dma->dma[cnt].table_index >= 1) { - IPAERR_RL("Invalid table index %d\n", + IPAERR("Invalid table index %d\n", dma->dma[cnt].table_index); ret = -EPERM; goto bail; @@ -623,7 +595,7 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) if (dma->dma[cnt].offset >= (ipa3_ctx->nat_mem.size_base_tables + 1) * NAT_TABLE_ENTRY_SIZE_BYTE) { - IPAERR_RL("Invalid offset %d\n", + IPAERR("Invalid offset %d\n", dma->dma[cnt].offset); ret = -EPERM; goto bail; @@ -635,7 +607,7 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) if (dma->dma[cnt].offset >= ipa3_ctx->nat_mem.size_expansion_tables * NAT_TABLE_ENTRY_SIZE_BYTE) { - IPAERR_RL("Invalid offset %d\n", + IPAERR("Invalid offset %d\n", dma->dma[cnt].offset); ret = -EPERM; goto bail; @@ -647,7 +619,7 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) if (dma->dma[cnt].offset >= (ipa3_ctx->nat_mem.size_base_tables + 1) * NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) { - IPAERR_RL("Invalid offset %d\n", + IPAERR("Invalid offset %d\n", dma->dma[cnt].offset); ret = -EPERM; goto bail; @@ -659,7 +631,7 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) if (dma->dma[cnt].offset >= ipa3_ctx->nat_mem.size_expansion_tables * NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) { - IPAERR_RL("Invalid offset %d\n", + IPAERR("Invalid offset %d\n", dma->dma[cnt].offset); ret = -EPERM; goto bail; @@ -668,7 +640,7 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) break; default: - IPAERR_RL("Invalid base_addr %d\n", + IPAERR("Invalid base_addr %d\n", dma->dma[cnt].base_addr); ret = -EPERM; goto bail; @@ -707,7 +679,7 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma) cmd_pyld = ipahal_construct_imm_cmd( IPA_IMM_CMD_NAT_DMA, &cmd, false); if (!cmd_pyld) { - IPAERR_RL("Fail to construct nat_dma imm cmd\n"); + IPAERR("Fail to construct nat_dma imm cmd\n"); continue; } desc[1].type = IPA_IMM_CMD_DESC; @@ -824,7 +796,7 @@ int ipa3_nat_del_cmd(struct ipa_ioc_v4_nat_del *del) cmd_pyld = ipahal_construct_imm_cmd( IPA_IMM_CMD_IP_V4_NAT_INIT, &cmd, false); if (!cmd_pyld) { - IPAERR_RL("Fail to construct ip_v4_nat_init imm cmd\n"); + IPAERR("Fail to construct ip_v4_nat_init imm cmd\n"); result = -EPERM; goto destroy_regwrt_imm_cmd; } @@ -861,22 +833,3 @@ destroy_regwrt_imm_cmd: bail: return result; } - -/** -* ipa3_del_nat_table() - Delete the NAT table -* @del: [in] delete table parameters -* -* Called by NAT client to delete the table -* -* Returns: 0 on success, negative on failure -*/ -int ipa3_del_nat_table(struct ipa_ioc_nat_ipv6ct_table_del *del) -{ - struct ipa_ioc_v4_nat_del tmp; - - tmp.table_index = del->table_index; - tmp.public_ip_addr = ipa3_ctx->nat_mem.public_ip_addr; - - return ipa3_nat_del_cmd(&tmp); -} - diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 571852c076eacd74e847eec4faf7091557cde3ae..0269bfba993f4bb8cc4fe7892aefd6f44e5be183 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -807,11 +807,6 @@ int ipa3_qmi_filter_notify_send( return -EINVAL; } - if (req->source_pipe_index == -1) { - IPAWANERR("Source pipe index invalid\n"); - return -EINVAL; - } - mutex_lock(&ipa3_qmi_lock); if (ipa3_qmi_ctx != NULL) { /* cache the qmi_filter_request */ @@ -1182,13 +1177,10 @@ void ipa3_qmi_service_exit(void) } /* clean the QMI msg cache */ - mutex_lock(&ipa3_qmi_lock); if (ipa3_qmi_ctx != NULL) { vfree(ipa3_qmi_ctx); ipa3_qmi_ctx = NULL; } - mutex_unlock(&ipa3_qmi_lock); - ipa3_svc_handle = 0; ipa3_qmi_modem_init_fin = false; ipa3_qmi_indication_fin = false; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h index e6f1e2ce0b7594b5fbcbd3750e60ef23fc84afec..d5d85030969658398ab037531738a8cfb56c9a39 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h @@ -121,31 +121,6 @@ extern struct elem_info ipa3_init_modem_driver_cmplt_resp_msg_data_v01_ei[]; extern struct elem_info ipa3_install_fltr_rule_req_ex_msg_data_v01_ei[]; extern struct elem_info ipa3_install_fltr_rule_resp_ex_msg_data_v01_ei[]; - extern struct elem_info - ipa3_install_fltr_rule_req_ex_msg_data_v01_ei[]; - extern struct elem_info - ipa3_install_fltr_rule_resp_ex_msg_data_v01_ei[]; - extern struct elem_info - ipa3_ul_firewall_rule_type_data_v01_ei[]; - extern struct elem_info - ipa3_ul_firewall_config_result_type_data_v01_ei[]; - extern struct elem_info - ipa3_per_client_stats_info_type_data_v01_ei[]; - extern struct elem_info - ipa3_enable_per_client_stats_req_msg_data_v01_ei[]; - extern struct elem_info - ipa3_enable_per_client_stats_resp_msg_data_v01_ei[]; - extern struct elem_info - ipa3_get_stats_per_client_req_msg_data_v01_ei[]; - extern struct elem_info - ipa3_get_stats_per_client_resp_msg_data_v01_ei[]; - extern struct elem_info - ipa3_configure_ul_firewall_rules_req_msg_data_v01_ei[]; - extern struct elem_info - ipa3_configure_ul_firewall_rules_resp_msg_data_v01_ei[]; - extern struct elem_info - ipa3_configure_ul_firewall_rules_ind_msg_data_v01_ei[]; - /** * struct ipa3_rmnet_context - IPA rmnet context * @ipa_rmnet_ssr: support modem SSR diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c index 746863732dc5a04663a74d689e5e6a15456349c7..6a5cb4891c02578337465907f20464e9dce2bfa0 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -16,8 +16,6 @@ #include -#include "ipa_qmi_service.h" - /* Type Definitions */ static struct elem_info ipa3_hdr_tbl_info_type_data_v01_ei[] = { { @@ -1757,36 +1755,6 @@ struct elem_info ipa3_fltr_installed_notif_req_msg_data_v01_ei[] = { struct ipa_fltr_installed_notif_req_msg_v01, rule_id), }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x18, - .offset = offsetof( - struct ipa_fltr_installed_notif_req_msg_v01, - dst_pipe_id_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x18, - .offset = offsetof( - struct ipa_fltr_installed_notif_req_msg_v01, - dst_pipe_id_len), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = QMI_IPA_MAX_CLIENT_DST_PIPES_V01, - .elem_size = sizeof(uint32_t), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x18, - .offset = offsetof( - struct ipa_fltr_installed_notif_req_msg_v01, - dst_pipe_id), - }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, @@ -2955,435 +2923,3 @@ struct elem_info ipa3_install_fltr_rule_resp_ex_msg_data_v01_ei[] = { .tlv_type = QMI_COMMON_TLV_TYPE, }, }; - -struct elem_info ipa3_per_client_stats_info_type_data_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - client_id), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - src_pipe_id), - }, - { - .data_type = QMI_UNSIGNED_8_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint64_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - num_ul_ipv4_bytes), - - }, - { - .data_type = QMI_UNSIGNED_8_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint64_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - num_ul_ipv6_bytes), - - }, - { - .data_type = QMI_UNSIGNED_8_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint64_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - num_dl_ipv4_bytes), - - }, - { - .data_type = QMI_UNSIGNED_8_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint64_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - num_dl_ipv6_bytes), - - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - num_ul_ipv4_pkts), - - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - num_ul_ipv6_pkts), - - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - num_dl_ipv4_pkts), - - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_per_client_stats_info_type_v01, - num_dl_ipv6_pkts), - - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info ipa3_ul_firewall_rule_type_data_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_ul_firewall_rule_type_v01, - ip_type), - }, - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct ipa_filter_rule_type_v01), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof(struct ipa_ul_firewall_rule_type_v01, - filter_rule), - .ei_array = ipa3_filter_rule_type_data_v01_ei, - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info ipa3_ul_firewall_config_result_type_data_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_ul_firewall_config_result_type_v01, - is_success), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - .offset = offsetof( - struct ipa_ul_firewall_config_result_type_v01, - mux_id), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info ipa3_enable_per_client_stats_req_msg_data_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct - ipa_enable_per_client_stats_req_msg_v01, - enable_per_client_stats), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info ipa3_enable_per_client_stats_resp_msg_data_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof( - struct ipa_enable_per_client_stats_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info ipa3_get_stats_per_client_req_msg_data_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof( - struct ipa_get_stats_per_client_req_msg_v01, - client_id), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof( - struct ipa_get_stats_per_client_req_msg_v01, - src_pipe_id), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof( - struct ipa_get_stats_per_client_req_msg_v01, - reset_stats_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof( - struct ipa_get_stats_per_client_req_msg_v01, - reset_stats), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info ipa3_get_stats_per_client_resp_msg_data_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof( - struct ipa_get_stats_per_client_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof( - struct ipa_get_stats_per_client_resp_msg_v01, - per_client_stats_list_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof( - struct ipa_get_stats_per_client_resp_msg_v01, - per_client_stats_list_len), - }, - { - .data_type = QMI_STRUCT, - .elem_len = QMI_IPA_MAX_PER_CLIENTS_V01, - .elem_size = - sizeof(struct ipa_per_client_stats_info_type_v01), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x10, - .offset = offsetof( - struct ipa_get_stats_per_client_resp_msg_v01, - per_client_stats_list), - .ei_array = - ipa3_per_client_stats_info_type_data_v01_ei, - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info - ipa3_configure_ul_firewall_rules_req_msg_data_v01_ei[] = { - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x1, - .offset = offsetof( - struct ipa_configure_ul_firewall_rules_req_msg_v01, - firewall_rules_list_len), - }, - { - .data_type = QMI_STRUCT, - .elem_len = QMI_IPA_MAX_UL_FIREWALL_RULES_V01, - .elem_size = sizeof(struct ipa_ul_firewall_rule_type_v01), - .is_array = VAR_LEN_ARRAY, - .tlv_type = 0x1, - .offset = offsetof( - struct ipa_configure_ul_firewall_rules_req_msg_v01, - firewall_rules_list), - .ei_array = - ipa3_ul_firewall_rule_type_data_v01_ei, - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint32_t), - .is_array = NO_ARRAY, - .tlv_type = 0x2, - .offset = offsetof( - struct ipa_configure_ul_firewall_rules_req_msg_v01, - mux_id), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof( - struct ipa_configure_ul_firewall_rules_req_msg_v01, - disable_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof( - struct ipa_configure_ul_firewall_rules_req_msg_v01, - disable), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof( - struct ipa_configure_ul_firewall_rules_req_msg_v01, - are_blacklist_filters_valid), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(uint8_t), - .is_array = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof( - struct ipa_configure_ul_firewall_rules_req_msg_v01, - are_blacklist_filters), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info - ipa3_configure_ul_firewall_rules_resp_msg_data_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof( - struct ipa_configure_ul_firewall_rules_resp_msg_v01, - resp), - .ei_array = get_qmi_response_type_v01_ei(), - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; - -struct elem_info - ipa3_configure_ul_firewall_rules_ind_msg_data_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof( - struct ipa_ul_firewall_config_result_type_v01), - .is_array = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof( - struct ipa_configure_ul_firewall_rules_ind_msg_v01, - result), - .ei_array = - ipa3_ul_firewall_config_result_type_data_v01_ei, - }, - { - .data_type = QMI_EOTI, - .is_array = NO_ARRAY, - .tlv_type = QMI_COMMON_TLV_TYPE, - }, -}; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index b7ba04519a33ec1ded816016d62ea16641fc2292..6197c9f64ca525951c5778d9b6fcf0cffa47a81e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -72,18 +72,11 @@ static int ipa_generate_rt_hw_rule(enum ipa_ip_type ip, if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) { struct ipa3_hdr_proc_ctx_entry *proc_ctx; proc_ctx = (entry->proc_ctx) ? : entry->hdr->proc_ctx; - if ((proc_ctx == NULL) || - (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) { - gen_params.hdr_type = IPAHAL_RT_RULE_HDR_NONE; - gen_params.hdr_ofst = 0; - } else { - gen_params.hdr_lcl = ipa3_ctx->hdr_proc_ctx_tbl_lcl; - gen_params.hdr_type = IPAHAL_RT_RULE_HDR_PROC_CTX; - gen_params.hdr_ofst = proc_ctx->offset_entry->offset + - ipa3_ctx->hdr_proc_ctx_tbl.start_offset; - } - } else if ((entry->hdr != NULL) && - (entry->hdr->cookie == IPA_HDR_COOKIE)) { + gen_params.hdr_lcl = ipa3_ctx->hdr_proc_ctx_tbl_lcl; + gen_params.hdr_type = IPAHAL_RT_RULE_HDR_PROC_CTX; + gen_params.hdr_ofst = proc_ctx->offset_entry->offset + + ipa3_ctx->hdr_proc_ctx_tbl.start_offset; + } else if (entry->hdr) { gen_params.hdr_lcl = ipa3_ctx->hdr_tbl_lcl; gen_params.hdr_type = IPAHAL_RT_RULE_HDR_RAW; gen_params.hdr_ofst = entry->hdr->offset_entry->offset; @@ -704,7 +697,7 @@ struct ipa3_rt_tbl *__ipa3_find_rt_tbl(enum ipa_ip_type ip, const char *name) struct ipa3_rt_tbl_set *set; if (strnlen(name, IPA_RESOURCE_NAME_MAX) == IPA_RESOURCE_NAME_MAX) { - IPAERR_RL("Name too long: %s\n", name); + IPAERR("Name too long: %s\n", name); return NULL; } @@ -730,7 +723,7 @@ int ipa3_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in) struct ipa3_rt_tbl *entry; if (in->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -756,7 +749,7 @@ static struct ipa3_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip, int max_tbl_indx; if (name == NULL) { - IPAERR_RL("no tbl name\n"); + IPAERR("no tbl name\n"); goto error; } @@ -769,7 +762,7 @@ static struct ipa3_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip, max(IPA_MEM_PART(v6_modem_rt_index_hi), IPA_MEM_PART(v6_apps_rt_index_hi)); } else { - IPAERR_RL("bad ip family type\n"); + IPAERR("bad ip family type\n"); goto error; } @@ -803,7 +796,7 @@ static struct ipa3_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip, INIT_LIST_HEAD(&entry->link); strlcpy(entry->name, name, IPA_RESOURCE_NAME_MAX); entry->set = set; - entry->cookie = IPA_RT_TBL_COOKIE; + entry->cookie = IPA_COOKIE; entry->in_sys[IPA_RULE_HASHABLE] = (ip == IPA_IP_v4) ? !ipa3_ctx->ip4_rt_tbl_hash_lcl : !ipa3_ctx->ip6_rt_tbl_hash_lcl; @@ -821,16 +814,12 @@ static struct ipa3_rt_tbl *__ipa_add_rt_tbl(enum ipa_ip_type ip, if (id < 0) { IPAERR("failed to add to tree\n"); WARN_ON(1); - goto ipa_insert_failed; } entry->id = id; } return entry; -ipa_insert_failed: - set->tbl_cnt--; - list_del(&entry->link); - idr_destroy(&entry->rule_ids); + fail_rt_idx_alloc: entry->cookie = 0; kmem_cache_free(ipa3_ctx->rt_tbl_cache, entry); @@ -844,13 +833,13 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry) u32 id; struct ipa3_rt_tbl_set *rset; - if (entry == NULL || (entry->cookie != IPA_RT_TBL_COOKIE)) { - IPAERR_RL("bad parms\n"); + if (entry == NULL || (entry->cookie != IPA_COOKIE)) { + IPAERR("bad parms\n"); return -EINVAL; } id = entry->id; if (ipa3_id_find(id) == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); return -EPERM; } @@ -858,10 +847,8 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry) ip = IPA_IP_v4; else if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v6]) ip = IPA_IP_v6; - else { + else WARN_ON(1); - return -EPERM; - } rset = &ipa3_ctx->reap_rt_tbl_set[ip]; @@ -898,14 +885,14 @@ static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule, if (rule->hdr_hdl) { *hdr = ipa3_id_find(rule->hdr_hdl); - if ((*hdr == NULL) || ((*hdr)->cookie != IPA_HDR_COOKIE)) { + if ((*hdr == NULL) || ((*hdr)->cookie != IPA_COOKIE)) { IPAERR("rt rule does not point to valid hdr\n"); return -EPERM; } } else if (rule->hdr_proc_ctx_hdl) { *proc_ctx = ipa3_id_find(rule->hdr_proc_ctx_hdl); if ((*proc_ctx == NULL) || - ((*proc_ctx)->cookie != IPA_PROC_HDR_COOKIE)) { + ((*proc_ctx)->cookie != IPA_COOKIE)) { IPAERR("rt rule does not point to valid proc ctx\n"); return -EPERM; @@ -928,7 +915,7 @@ static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry, goto error; } INIT_LIST_HEAD(&(*entry)->link); - (*(entry))->cookie = IPA_RT_RULE_COOKIE; + (*(entry))->cookie = IPA_COOKIE; (*(entry))->rule = *rule; (*(entry))->tbl = tbl; (*(entry))->hdr = hdr; @@ -996,8 +983,8 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, tbl = __ipa_add_rt_tbl(ip, name); - if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) { - IPAERR_RL("failed adding rt tbl name = %s\n", + if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) { + IPAERR("failed adding rt tbl name = %s\n", name ? name : ""); goto error; } @@ -1007,8 +994,8 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && (tbl->rule_cnt > 0) && (at_rear != 0)) { - IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d at_rear=%d" - , tbl->rule_cnt, at_rear); + IPAERR("cannot add rule at end of tbl rule_cnt=%d at_rear=%d\n", + tbl->rule_cnt, at_rear); goto error; } @@ -1078,7 +1065,7 @@ int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) int ret; if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1088,7 +1075,7 @@ int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) &rules->rules[i].rule, rules->rules[i].at_rear, &rules->rules[i].rt_rule_hdl)) { - IPAERR_RL("failed to add rt rule %d\n", i); + IPAERR("failed to add rt rule %d\n", i); rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; @@ -1124,43 +1111,36 @@ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules) struct ipa3_rt_entry *entry = NULL; if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); tbl = __ipa3_find_rt_tbl(rules->ip, rules->rt_tbl_name); - if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) { - IPAERR_RL("failed finding rt tbl name = %s\n", + if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) { + IPAERR("failed finding rt tbl name = %s\n", rules->rt_tbl_name ? rules->rt_tbl_name : ""); ret = -EINVAL; goto bail; } if (tbl->rule_cnt <= 0) { - IPAERR_RL("tbl->rule_cnt <= 0"); + IPAERR("tbl->rule_cnt <= 0"); ret = -EINVAL; goto bail; } entry = ipa3_id_find(rules->add_after_hdl); if (!entry) { - IPAERR_RL("failed finding rule %d in rt tbls\n", + IPAERR("failed finding rule %d in rt tbls\n", rules->add_after_hdl); ret = -EINVAL; goto bail; } - if (entry->cookie != IPA_RT_RULE_COOKIE) { - IPAERR_RL("Invalid cookie value = %u rule %d in rt tbls\n", - entry->cookie, rules->add_after_hdl); - ret = -EINVAL; - goto bail; - } - if (entry->tbl != tbl) { - IPAERR_RL("given rt rule does not match the table\n"); + IPAERR("given rt rule does not match the table\n"); ret = -EINVAL; goto bail; } @@ -1171,7 +1151,7 @@ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules) */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && (&entry->link == tbl->head_rt_rule_list.prev)) { - IPAERR_RL("cannot add rule at end of tbl rule_cnt=%d\n", + IPAERR("cannot add rule at end of tbl rule_cnt=%d\n", tbl->rule_cnt); ret = -EINVAL; goto bail; @@ -1188,7 +1168,7 @@ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules) &rules->rules[i].rule, &rules->rules[i].rt_rule_hdl, &entry)) { - IPAERR_RL("failed to add rt rule %d\n", i); + IPAERR("failed to add rt rule %d\n", i); rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; @@ -1197,7 +1177,7 @@ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules) if (rules->commit) if (ipa3_ctx->ctrl->ipa3_commit_rt(rules->ip)) { - IPAERR_RL("failed to commit\n"); + IPAERR("failed to commit\n"); ret = -EPERM; goto bail; } @@ -1218,12 +1198,12 @@ int __ipa3_del_rt_rule(u32 rule_hdl) entry = ipa3_id_find(rule_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); return -EINVAL; } - if (entry->cookie != IPA_RT_RULE_COOKIE) { - IPAERR_RL("bad params\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad params\n"); return -EINVAL; } @@ -1239,7 +1219,7 @@ int __ipa3_del_rt_rule(u32 rule_hdl) idr_remove(&entry->tbl->rule_ids, entry->rule_id); if (entry->tbl->rule_cnt == 0 && entry->tbl->ref_cnt == 0) { if (__ipa_del_rt_tbl(entry->tbl)) - IPAERR_RL("fail to del RT tbl\n"); + IPAERR("fail to del RT tbl\n"); } entry->cookie = 0; id = entry->id; @@ -1266,14 +1246,14 @@ int ipa3_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls) int ret; if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); for (i = 0; i < hdls->num_hdls; i++) { if (__ipa3_del_rt_rule(hdls->hdl[i].hdl)) { - IPAERR_RL("failed to del rt rule %i\n", i); + IPAERR("failed to del rt rule %i\n", i); hdls->hdl[i].status = IPA_RT_STATUS_OF_DEL_FAILED; } else { hdls->hdl[i].status = 0; @@ -1306,7 +1286,7 @@ int ipa3_commit_rt(enum ipa_ip_type ip) int ret; if (ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1350,7 +1330,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip) int id; if (ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } @@ -1366,7 +1346,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip) * filtering rules point to routing tables */ if (ipa3_reset_flt(ip)) - IPAERR_RL("fail to reset flt ip=%d\n", ip); + IPAERR("fail to reset flt ip=%d\n", ip); set = &ipa3_ctx->rt_tbl_set[ip]; rset = &ipa3_ctx->reap_rt_tbl_set[ip]; @@ -1455,14 +1435,14 @@ int ipa3_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup) int result = -EFAULT; if (lookup == NULL || lookup->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); entry = __ipa3_find_rt_tbl(lookup->ip, lookup->name); - if (entry && entry->cookie == IPA_RT_TBL_COOKIE) { + if (entry && entry->cookie == IPA_COOKIE) { if (entry->ref_cnt == U32_MAX) { - IPAERR_RL("fail: ref count crossed limit\n"); + IPAERR("fail: ref count crossed limit\n"); goto ret; } entry->ref_cnt++; @@ -1470,7 +1450,7 @@ int ipa3_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup) /* commit for get */ if (ipa3_ctx->ctrl->ipa3_commit_rt(lookup->ip)) - IPAERR_RL("fail to commit RT tbl\n"); + IPAERR("fail to commit RT tbl\n"); result = 0; } @@ -1493,18 +1473,18 @@ int ipa3_put_rt_tbl(u32 rt_tbl_hdl) { struct ipa3_rt_tbl *entry; enum ipa_ip_type ip = IPA_IP_MAX; - int result = 0; + int result; mutex_lock(&ipa3_ctx->lock); entry = ipa3_id_find(rt_tbl_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); result = -EINVAL; goto ret; } - if ((entry->cookie != IPA_RT_TBL_COOKIE) || entry->ref_cnt == 0) { - IPAERR_RL("bad parms\n"); + if ((entry->cookie != IPA_COOKIE) || entry->ref_cnt == 0) { + IPAERR("bad parms\n"); result = -EINVAL; goto ret; } @@ -1513,21 +1493,18 @@ int ipa3_put_rt_tbl(u32 rt_tbl_hdl) ip = IPA_IP_v4; else if (entry->set == &ipa3_ctx->rt_tbl_set[IPA_IP_v6]) ip = IPA_IP_v6; - else { + else WARN_ON(1); - result = -EINVAL; - goto ret; - } entry->ref_cnt--; if (entry->ref_cnt == 0 && entry->rule_cnt == 0) { IPADBG("zero ref_cnt, delete rt tbl (idx=%u)\n", entry->idx); if (__ipa_del_rt_tbl(entry)) - IPAERR_RL("fail to del RT tbl\n"); + IPAERR("fail to del RT tbl\n"); /* commit for put */ if (ipa3_ctx->ctrl->ipa3_commit_rt(ip)) - IPAERR_RL("fail to commit RT tbl\n"); + IPAERR("fail to commit RT tbl\n"); } result = 0; @@ -1547,27 +1524,26 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) if (rtrule->rule.hdr_hdl) { hdr = ipa3_id_find(rtrule->rule.hdr_hdl); - if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) { - IPAERR_RL("rt rule does not point to valid hdr\n"); + if ((hdr == NULL) || (hdr->cookie != IPA_COOKIE)) { + IPAERR("rt rule does not point to valid hdr\n"); goto error; } } else if (rtrule->rule.hdr_proc_ctx_hdl) { proc_ctx = ipa3_id_find(rtrule->rule.hdr_proc_ctx_hdl); - if ((proc_ctx == NULL) || - (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) { - IPAERR_RL("rt rule does not point to valid proc ctx\n"); + if ((proc_ctx == NULL) || (proc_ctx->cookie != IPA_COOKIE)) { + IPAERR("rt rule does not point to valid proc ctx\n"); goto error; } } entry = ipa3_id_find(rtrule->rt_rule_hdl); if (entry == NULL) { - IPAERR_RL("lookup failed\n"); + IPAERR("lookup failed\n"); goto error; } - if (entry->cookie != IPA_RT_RULE_COOKIE) { - IPAERR_RL("bad params\n"); + if (entry->cookie != IPA_COOKIE) { + IPAERR("bad params\n"); goto error; } @@ -1608,14 +1584,14 @@ int ipa3_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *hdls) int result; if (hdls == NULL || hdls->num_rules == 0 || hdls->ip >= IPA_IP_MAX) { - IPAERR_RL("bad parm\n"); + IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); for (i = 0; i < hdls->num_rules; i++) { if (__ipa_mdfy_rt_rule(&hdls->rules[i])) { - IPAERR_RL("failed to mdfy rt rule %i\n", i); + IPAERR("failed to mdfy rt rule %i\n", i); hdls->rules[i].status = IPA_RT_STATUS_OF_MDFY_FAILED; } else { hdls->rules[i].status = 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index d3837a05fdc2c7bf0cff4e4f1fe27c4e9d94539e..e49bdc8c7083df525adbc2be0685c3c4c5666abf 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -1664,7 +1664,7 @@ int ipa3_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id) if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || ipa3_ctx->ep[clnt_hdl].valid == 0) { - IPAERR_RL("bad parm, %d\n", clnt_hdl); + IPAERR("bad parm, %d\n", clnt_hdl); return -EINVAL; } @@ -1677,7 +1677,7 @@ int ipa3_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id) ep = &ipa3_ctx->ep[clnt_hdl]; if (!(ep->uc_offload_state & IPA_WDI_CONNECTED)) { - IPAERR_RL("WDI channel bad state %d\n", ep->uc_offload_state); + IPAERR("WDI channel bad state %d\n", ep->uc_offload_state); return -EFAULT; } IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl)); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 545c2b599a6f069d1b13254338f0c3935f08c558..6647f919a577b4fb5acc1d0a52d957d69b8038ef 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -794,28 +794,6 @@ void _ipa_sram_settings_read_v3_0(void) ipa3_ctx->ip6_flt_tbl_nhash_lcl = 0; } -/** - * ipa3_cfg_clkon_cfg() - configure IPA clkon_cfg - * @clkon_cfg: IPA clkon_cfg - * - * Return codes: - * 0: success - */ -int ipa3_cfg_clkon_cfg(struct ipahal_reg_clkon_cfg *clkon_cfg) -{ - - IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - - IPADBG("cgc_open_misc = %d\n", - clkon_cfg->cgc_open_misc); - - ipahal_write_reg_fields(IPA_CLKON_CFG, clkon_cfg); - - IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); - - return 0; -} - /** * ipa3_cfg_route() - configure IPA route * @route: IPA route @@ -860,7 +838,7 @@ int ipa3_cfg_route(struct ipahal_reg_route *route) */ int ipa3_cfg_filter(u32 disable) { - IPAERR_RL("Filter disable is not supported!\n"); + IPAERR("Filter disable is not supported!\n"); return -EPERM; } @@ -950,7 +928,7 @@ int ipa3_get_ep_mapping(enum ipa_client_type client) int ipa_ep_idx; if (client >= IPA_CLIENT_MAX || client < 0) { - IPAERR_RL("Bad client number! client =%d\n", client); + IPAERR("Bad client number! client =%d\n", client); return IPA_EP_NOT_ALLOCATED; } @@ -2023,19 +2001,19 @@ int ipa3_write_qmap_id(struct ipa_ioc_write_qmapid *param_in) int result = -EINVAL; if (param_in->client >= IPA_CLIENT_MAX) { - IPAERR_RL("bad parm client:%d\n", param_in->client); + IPAERR("bad parm client:%d\n", param_in->client); goto fail; } ipa_ep_idx = ipa3_get_ep_mapping(param_in->client); if (ipa_ep_idx == -1) { - IPAERR_RL("Invalid client.\n"); + IPAERR("Invalid client.\n"); goto fail; } ep = &ipa3_ctx->ep[ipa_ep_idx]; if (!ep->valid) { - IPAERR_RL("EP not allocated.\n"); + IPAERR("EP not allocated.\n"); goto fail; } @@ -2048,7 +2026,7 @@ int ipa3_write_qmap_id(struct ipa_ioc_write_qmapid *param_in) ipa3_ctx->ep[ipa_ep_idx].cfg.meta = meta; result = ipa3_write_qmapid_wdi_pipe(ipa_ep_idx, meta.qmap_id); if (result) - IPAERR_RL("qmap_id %d write failed on ep=%d\n", + IPAERR("qmap_id %d write failed on ep=%d\n", meta.qmap_id, ipa_ep_idx); result = 0; } @@ -2861,7 +2839,7 @@ static int ipa3_tag_generate_force_close_desc(struct ipa3_desc desc[], IPAHAL_FULL_PIPELINE_CLEAR; reg_write_agg_close.offset = ipahal_get_reg_ofst(IPA_AGGR_FORCE_CLOSE); - ipahal_get_aggr_force_close_valmask(i, &valmask); + ipahal_get_aggr_force_close_valmask(1<cgc_open_misc, - IPA_CLKON_CFG_CGC_OPEN_MISC_SHFT, - IPA_CLKON_CFG_CGC_OPEN_MISC_BMSK); -} - static void ipareg_construct_route(enum ipahal_reg_name reg, const void *fields, u32 *val) { @@ -1172,9 +1159,6 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { /* IPAv3.1 */ - [IPA_HW_v3_1][IPA_CLKON_CFG] = { - ipareg_construct_clkon_cfg, ipareg_parse_dummy, - 0x00000044, 0}, [IPA_HW_v3_1][IPA_IRQ_SUSPEND_INFO_EE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, 0x00003030, 0x1000}, @@ -1576,11 +1560,6 @@ void ipahal_get_aggr_force_close_valmask(int ep_idx, IPA_AGGR_FORCE_CLOSE_AGGR_FORCE_CLOSE_PIPE_BITMAP_BMSK_V3_5; } - if (ep_idx > (sizeof(valmask->val) * 8 - 1)) { - IPAHAL_ERR("too big ep_idx %d\n", ep_idx); - ipa_assert(); - return; - } IPA_SETFIELD_IN_REG(valmask->val, 1 << ep_idx, shft, bmsk); valmask->mask = bmsk << shft; } @@ -1612,3 +1591,20 @@ void ipahal_get_fltrt_hash_flush_valmask( valmask->mask = valmask->val; } + +void ipahal_get_status_ep_valmask(int pipe_num, + struct ipahal_reg_valmask *valmask) +{ + if (!valmask) { + IPAHAL_ERR("Input error\n"); + return; + } + + valmask->val = + (pipe_num & IPA_ENDP_STATUS_n_STATUS_ENDP_BMSK) << + IPA_ENDP_STATUS_n_STATUS_ENDP_SHFT; + + valmask->mask = + IPA_ENDP_STATUS_n_STATUS_ENDP_BMSK << + IPA_ENDP_STATUS_n_STATUS_ENDP_SHFT; +} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h index 9f32c071cb68c3ccc34b9ddb590032e50346933a..c37415f13380f6183881dd46fac5539eba156100 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h @@ -22,7 +22,6 @@ * array as well. */ enum ipahal_reg_name { - IPA_CLKON_CFG, IPA_ROUTE, IPA_IRQ_STTS_EE_n, IPA_IRQ_EN_EE_n, @@ -90,14 +89,6 @@ enum ipahal_reg_name { IPA_REG_MAX, }; -/* - * struct ipahal_reg_clkon_cfg - IPA clock on configuration register - * @cgc_open_misc: clock gating needs for MISC - */ -struct ipahal_reg_clkon_cfg { - u32 cgc_open_misc; -}; - /* * struct ipahal_reg_route - IPA route register * @route_dis: route disable @@ -467,6 +458,8 @@ void ipahal_get_aggr_force_close_valmask(int ep_idx, void ipahal_get_fltrt_hash_flush_valmask( struct ipahal_reg_fltrt_hash_flush *flush, struct ipahal_reg_valmask *valmask); +void ipahal_get_status_ep_valmask(int pipe_num, + struct ipahal_reg_valmask *valmask); #endif /* _IPAHAL_REG_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h index 37458c4d0697ca7aea27fddea00b13ce34d80fbe..ac97e5ac0494c977b00b1a593c8dc8a8e4821f48 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h @@ -21,9 +21,6 @@ int ipahal_reg_init(enum ipa_hw_type ipa_hw_type); #define IPA_GETFIELD_FROM_REG(reg, shift, mask) \ (((reg) & (mask)) >> (shift)) -/* IPA_CLKON_CFG register */ -#define IPA_CLKON_CFG_CGC_OPEN_MISC_SHFT 0x3 -#define IPA_CLKON_CFG_CGC_OPEN_MISC_BMSK 0x8 /* IPA_ROUTE register */ #define IPA_ROUTE_ROUTE_DIS_SHFT 0x0 diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index a1d3d05f2f72005777326ad431a9c861965151fa..039bc7da515314a723b87e2ae8a1ae8bc66ef316 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -423,8 +423,6 @@ int ipa3_copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01 { int i, j; - /* prevent multi-threads accessing rmnet_ipa3_ctx->num_q6_rules */ - mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock); if (rule_req->filter_spec_ex_list_valid == true) { rmnet_ipa3_ctx->num_q6_rules = rule_req->filter_spec_ex_list_len; @@ -433,8 +431,6 @@ int ipa3_copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01 } else { rmnet_ipa3_ctx->num_q6_rules = 0; IPAWANERR("got no UL rules from modem\n"); - mutex_unlock(&rmnet_ipa3_ctx-> - add_mux_channel_lock); return -EINVAL; } @@ -637,13 +633,9 @@ failure: rmnet_ipa3_ctx->num_q6_rules = 0; memset(ipa3_qmi_ctx->q6_ul_filter_rule, 0, sizeof(ipa3_qmi_ctx->q6_ul_filter_rule)); - mutex_unlock(&rmnet_ipa3_ctx-> - add_mux_channel_lock); return -EINVAL; success: - mutex_unlock(&rmnet_ipa3_ctx-> - add_mux_channel_lock); return 0; } @@ -710,11 +702,6 @@ static int ipa3_wwan_add_ul_flt_rule_to_ipa(void) /* send ipa_fltr_installed_notif_req_msg_v01 to Q6*/ req->source_pipe_index = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_PROD); - if (req->source_pipe_index == IPA_EP_NOT_ALLOCATED) { - IPAWANERR("ep mapping failed\n"); - retval = -EFAULT; - } - req->install_status = QMI_RESULT_SUCCESS_V01; req->rule_id_valid = 1; req->rule_id_len = rmnet_ipa3_ctx->num_q6_rules; @@ -1445,13 +1432,8 @@ static int handle3_egress_format(struct net_device *dev, if (rmnet_ipa3_ctx->num_q6_rules != 0) { /* already got Q6 UL filter rules*/ - if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false) { - /* prevent multi-threads accessing num_q6_rules */ - mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock); + if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false) rc = ipa3_wwan_add_ul_flt_rule_to_ipa(); - mutex_unlock(&rmnet_ipa3_ctx-> - add_mux_channel_lock); - } if (rc) IPAWANERR("install UL rules failed\n"); else @@ -1965,9 +1947,7 @@ void ipa3_q6_deinitialize_rm(void) if (ret < 0) IPAWANERR("Error deleting resource %d, ret=%d\n", IPA_RM_RESOURCE_Q6_PROD, ret); - - if (rmnet_ipa3_ctx->rm_q6_wq) - destroy_workqueue(rmnet_ipa3_ctx->rm_q6_wq); + destroy_workqueue(rmnet_ipa3_ctx->rm_q6_wq); } static void ipa3_wake_tx_queue(struct work_struct *work) @@ -2307,10 +2287,7 @@ timer_init_err: IPAWANERR("Error deleting resource %d, ret=%d\n", IPA_RM_RESOURCE_WWAN_0_PROD, ret); create_rsrc_err: - - if (!atomic_read(&rmnet_ipa3_ctx->is_ssr)) - ipa3_q6_deinitialize_rm(); - + ipa3_q6_deinitialize_rm(); q6_init_err: free_netdev(dev); rmnet_ipa3_ctx->wwan_priv = NULL; diff --git a/drivers/platform/msm/mhi/mhi_iface.c b/drivers/platform/msm/mhi/mhi_iface.c index ce6d1257cfbb91828e8058df79081a939d739255..a5936ea5a6aafa60bebb802a518686f1296ba8cd 100644 --- a/drivers/platform/msm/mhi/mhi_iface.c +++ b/drivers/platform/msm/mhi/mhi_iface.c @@ -509,7 +509,7 @@ static int __exit mhi_plat_remove(struct platform_device *pdev) static int __init mhi_init(void) { - int r = -EAGAIN; + int r; struct mhi_device_driver *mhi_dev_drv; mhi_dev_drv = kmalloc(sizeof(*mhi_dev_drv), GFP_KERNEL); diff --git a/drivers/platform/msm/mhi/mhi_init.c b/drivers/platform/msm/mhi/mhi_init.c index a95579241524c60a1333c3f9318f5605709b8faf..b6edf707798b63c040ec82a472803b2df8aecf16 100644 --- a/drivers/platform/msm/mhi/mhi_init.c +++ b/drivers/platform/msm/mhi/mhi_init.c @@ -141,7 +141,7 @@ int init_mhi_dev_mem(struct mhi_device_ctxt *mhi_dev_ctxt) size_t mhi_mem_index = 0, ring_len; void *dev_mem_start; dma_addr_t dma_dev_mem_start; - int i; + int i, r; mhi_dev_ctxt->dev_space.dev_mem_len = calculate_mhi_space(mhi_dev_ctxt); @@ -244,7 +244,7 @@ err_ev_alloc: mhi_dev_ctxt->dev_space.dev_mem_len, mhi_dev_ctxt->dev_space.dev_mem_start, mhi_dev_ctxt->dev_space.dma_dev_mem_start); - return -EFAULT; + return r; } static int mhi_init_events(struct mhi_device_ctxt *mhi_dev_ctxt) diff --git a/drivers/platform/msm/mhi/mhi_mmio_ops.c b/drivers/platform/msm/mhi/mhi_mmio_ops.c index 18d0334ce1ec4ad509796860500ea0019456cccd..a991a2e68b34ed69dc4a3b79bdfd609358fbbacd 100644 --- a/drivers/platform/msm/mhi/mhi_mmio_ops.c +++ b/drivers/platform/msm/mhi/mhi_mmio_ops.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -109,6 +109,7 @@ int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt) u64 pcie_dword_val = 0; u32 pcie_word_val = 0; u32 i = 0; + int ret_val; mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "~~~ Initializing MMIO ~~~\n"); @@ -130,7 +131,7 @@ int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt) if (mhi_dev_ctxt->core.mhi_ver != MHI_VERSION) { mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Bad MMIO version, 0x%x\n", mhi_dev_ctxt->core.mhi_ver); - return -ENXIO; + return ret_val; } /* Enable the channels */ diff --git a/drivers/platform/msm/mhi/mhi_sys.c b/drivers/platform/msm/mhi/mhi_sys.c index b1434daf1f60296255350a6323291752753753c7..1d9282627d4ef33a61d9d1111e85c07a553cbcb3 100644 --- a/drivers/platform/msm/mhi/mhi_sys.c +++ b/drivers/platform/msm/mhi/mhi_sys.c @@ -329,7 +329,7 @@ uintptr_t mhi_p2v_addr(struct mhi_device_ctxt *mhi_dev_ctxt, enum MHI_RING_TYPE type, u32 chan, uintptr_t phy_ptr) { - uintptr_t virtual_ptr = 0; + uintptr_t virtual_ptr; struct mhi_ring_ctxt *cs = &mhi_dev_ctxt->dev_space.ring_ctxt; switch (type) { @@ -358,7 +358,7 @@ dma_addr_t mhi_v2p_addr(struct mhi_device_ctxt *mhi_dev_ctxt, enum MHI_RING_TYPE type, u32 chan, uintptr_t va_ptr) { - dma_addr_t phy_ptr = 0; + dma_addr_t phy_ptr; struct mhi_ring_ctxt *cs = &mhi_dev_ctxt->dev_space.ring_ctxt; switch (type) { diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c index 9c35eeb177d93ce428e5e88952bacd930a599212..4563810d7e5bbdac03d3ad1a42b420b563e85ce8 100644 --- a/drivers/platform/msm/mhi_uci/mhi_uci.c +++ b/drivers/platform/msm/mhi_uci/mhi_uci.c @@ -326,6 +326,73 @@ static int mhi_init_inbound(struct uci_client *client_handle) return ret_val; } +static int mhi_uci_send_packet(struct mhi_client_handle **client_handle, + void *buf, + u32 size) +{ + u32 nr_avail_trbs = 0; + u32 i = 0; + void *data_loc = NULL; + unsigned long memcpy_result = 0; + int data_left_to_insert = 0; + size_t data_to_insert_now = 0; + u32 data_inserted_so_far = 0; + int ret_val = 0; + struct uci_client *uci_handle; + struct uci_buf *uci_buf; + + uci_handle = container_of(client_handle, struct uci_client, + out_attr.mhi_handle); + + nr_avail_trbs = atomic_read(&uci_handle->out_attr.avail_pkts); + data_left_to_insert = size; + + for (i = 0; i < nr_avail_trbs; ++i) { + data_to_insert_now = min_t(size_t, data_left_to_insert, + uci_handle->out_attr.max_packet_size); + data_loc = kmalloc(data_to_insert_now + sizeof(*uci_buf), + GFP_KERNEL); + if (!data_loc) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "Failed to allocate memory 0x%zx\n", + data_to_insert_now); + return -ENOMEM; + } + uci_buf = data_loc + data_to_insert_now; + uci_buf->data = data_loc; + uci_buf->pkt_id = uci_handle->out_attr.pkt_count++; + memcpy_result = copy_from_user(uci_buf->data, + buf + data_inserted_so_far, + data_to_insert_now); + if (memcpy_result) + goto error_xfer; + + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "At trb i = %d/%d, size = %lu, id %llu chan %d\n", + i, nr_avail_trbs, data_to_insert_now, uci_buf->pkt_id, + uci_handle->out_attr.chan_id); + ret_val = mhi_queue_xfer(*client_handle, uci_buf->data, + data_to_insert_now, MHI_EOT); + if (ret_val) { + goto error_xfer; + } else { + data_left_to_insert -= data_to_insert_now; + data_inserted_so_far += data_to_insert_now; + atomic_inc(&uci_handle->out_pkt_pend_ack); + atomic_dec(&uci_handle->out_attr.avail_pkts); + list_add_tail(&uci_buf->node, + &uci_handle->out_attr.buf_head); + } + if (!data_left_to_insert) + break; + } + return data_inserted_so_far; + +error_xfer: + kfree(uci_buf->data); + return data_inserted_so_far; +} + static int mhi_uci_send_status_cmd(struct uci_client *client) { void *buf = NULL; @@ -896,11 +963,18 @@ static ssize_t mhi_uci_client_write(struct file *file, goto sys_interrupt; } - while (count) { - size_t xfer_size; - void *data_loc = NULL; - struct uci_buf *uci_buf; + while (bytes_transferrd != count) { + ret_val = mhi_uci_send_packet(&chan_attr->mhi_handle, + (void *)buf, count); + if (ret_val < 0) + goto sys_interrupt; + bytes_transferrd += ret_val; + if (bytes_transferrd == count) + break; + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "No descriptors available, did we poll, chan %d?\n", + chan); mutex_unlock(&chan_attr->chan_lock); ret_val = wait_event_interruptible(chan_attr->wq, (atomic_read(&chan_attr->avail_pkts) || @@ -917,37 +991,6 @@ static ssize_t mhi_uci_client_write(struct file *file, ret_val = -ERESTARTSYS; goto sys_interrupt; } - - xfer_size = min_t(size_t, count, chan_attr->max_packet_size); - data_loc = kmalloc(xfer_size + sizeof(*uci_buf), GFP_KERNEL); - if (!data_loc) { - uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, - "Failed to allocate memory %lu\n", xfer_size); - ret_val = -ENOMEM; - goto sys_interrupt; - } - - uci_buf = data_loc + xfer_size; - uci_buf->data = data_loc; - uci_buf->pkt_id = uci_handle->out_attr.pkt_count++; - ret_val = copy_from_user(uci_buf->data, buf, xfer_size); - if (unlikely(ret_val)) { - kfree(uci_buf->data); - goto sys_interrupt; - } - ret_val = mhi_queue_xfer(chan_attr->mhi_handle, uci_buf->data, - xfer_size, MHI_EOT); - if (unlikely(ret_val)) { - kfree(uci_buf->data); - goto sys_interrupt; - } - - bytes_transferrd += xfer_size; - count -= xfer_size; - buf += xfer_size; - atomic_inc(&uci_handle->out_pkt_pend_ack); - atomic_dec(&uci_handle->out_attr.avail_pkts); - list_add_tail(&uci_buf->node, &uci_handle->out_attr.buf_head); } mutex_unlock(&chan_attr->chan_lock); @@ -1030,7 +1073,7 @@ error_dts: static void process_rs232_state(struct uci_client *ctrl_client, struct mhi_result *result) { - struct rs232_ctrl_msg *rs232_pkt = result->buf_addr; + struct rs232_ctrl_msg *rs232_pkt; struct uci_client *client = NULL; struct mhi_uci_ctxt_t *uci_ctxt = ctrl_client->uci_ctxt; u32 msg_id; @@ -1051,6 +1094,7 @@ static void process_rs232_state(struct uci_client *ctrl_client, sizeof(struct rs232_ctrl_msg)); goto error_size; } + rs232_pkt = result->buf_addr; MHI_GET_CTRL_DEST_ID(CTRL_DEST_ID, rs232_pkt, chan); for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++) if (chan == uci_ctxt->client_handles[i].out_attr.chan_id || diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c index bc15ef2a5b2ba02107f025da58e3895680448324..4f7d27db8deed31c5ddfb01c508ce6c15a4a582e 100644 --- a/drivers/platform/msm/msm_ext_display.c +++ b/drivers/platform/msm/msm_ext_display.c @@ -39,8 +39,6 @@ struct msm_ext_disp { struct list_head display_list; struct mutex lock; struct completion hpd_comp; - bool update_audio; - u32 flags; }; static int msm_ext_disp_get_intf_data(struct msm_ext_disp *ext_disp, @@ -342,8 +340,6 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, goto end; } - ext_disp->flags = flags; - if (state == EXT_DISPLAY_CABLE_CONNECT) { if (!msm_ext_disp_validate_connect(ext_disp, type, flags)) { pr_err("Display interface (%s) already connected\n", @@ -574,7 +570,6 @@ static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp, { int ret = 0; struct msm_ext_disp_audio_codec_ops *ops = ext_disp->ops; - ext_disp->update_audio = false; if (!(flags & MSM_EXT_DISP_HPD_AUDIO)) { pr_debug("skipping audio ops setup for display (%s)\n", @@ -584,10 +579,6 @@ static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp, if (!ops) { pr_err("Invalid audio ops\n"); - if (state == EXT_DISPLAY_CABLE_CONNECT) { - /* update audio ops once audio codec gets registered */ - ext_disp->update_audio = true; - } ret = -EINVAL; goto end; } @@ -691,18 +682,6 @@ int msm_ext_disp_register_audio_codec(struct platform_device *pdev, pr_debug("audio codec registered\n"); - mutex_lock(&ext_disp->lock); - if (ext_disp->update_audio) { - msm_ext_disp_update_audio_ops(ext_disp, ext_disp->current_disp, - EXT_DISPLAY_CABLE_CONNECT, ext_disp->flags); - - msm_ext_disp_process_audio(ext_disp, ext_disp->current_disp, - EXT_DISPLAY_CABLE_CONNECT, ext_disp->flags); - - ext_disp->update_audio = false; - } - mutex_unlock(&ext_disp->lock); - return ret; } @@ -824,8 +803,6 @@ static int msm_ext_disp_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ext_disp->display_list); init_completion(&ext_disp->hpd_comp); ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; - ext_disp->flags = 0; - ext_disp->update_audio = false; return ret; diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c index 0fec8acde96ca776e273f884d43884190e7723a2..c328865641ce74c25f5685649e0f66a0a015d515 100644 --- a/drivers/platform/msm/qpnp-revid.c +++ b/drivers/platform/msm/qpnp-revid.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -18,6 +23,9 @@ #include #include #include +#ifdef CONFIG_RAMDUMP_TAGS +#include +#endif #define REVID_REVISION1 0x0 #define REVID_REVISION2 0x1 @@ -27,7 +35,6 @@ #define REVID_SUBTYPE 0x5 #define REVID_STATUS1 0x8 #define REVID_SPARE_0 0x60 -#define REVID_TP_REV 0xf1 #define REVID_FAB_ID 0xf2 #define QPNP_REVID_DEV_NAME "qcom,qpnp-revid" @@ -127,6 +134,11 @@ static size_t build_pmic_string(char *buf, size_t n, int sid, u8 subtype, u8 rev1, u8 rev2, u8 rev3, u8 rev4) { size_t pos = 0; +#ifdef CONFIG_RAMDUMP_TAGS + char tag_name[64]; + char tag_data[64]; + int version_pos = 0; +#endif /* * In early versions of PM8941 and PM8226, the major revision number * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0). @@ -145,11 +157,21 @@ static size_t build_pmic_string(char *buf, size_t n, int sid, else pos += snprintf(buf + pos, n - pos, ": %s", pmic_names[subtype]); +#ifdef CONFIG_RAMDUMP_TAGS + snprintf(tag_name, sizeof(tag_name), "pmic_%s_revision_str", + pmic_names[(subtype < ARRAY_SIZE(pmic_names)) ? subtype : 0]); + version_pos = pos + 1; +#endif pos += snprintf(buf + pos, n - pos, " v%d.%d", rev4, rev3); if (rev2 || rev1) pos += snprintf(buf + pos, n - pos, ".%d", rev2); if (rev1) pos += snprintf(buf + pos, n - pos, ".%d", rev1); + +#ifdef CONFIG_RAMDUMP_TAGS + snprintf(tag_data, sizeof(tag_data), "%s", buf + version_pos); + rdtags_add_tag(tag_name, tag_data, strlen(tag_data)); +#endif return pos; } @@ -158,9 +180,9 @@ static size_t build_pmic_string(char *buf, size_t n, int sid, static int qpnp_revid_probe(struct platform_device *pdev) { u8 rev1, rev2, rev3, rev4, pmic_type, pmic_subtype, pmic_status; - u8 option1, option2, option3, option4, spare0; + u8 option1, option2, option3, option4, spare0, fab_id; unsigned int base; - int rc, fab_id, tp_rev; + int rc; char pmic_string[PMIC_STRING_MAXLENGTH] = {'\0'}; struct revid_chip *revid_chip; struct regmap *regmap; @@ -208,11 +230,6 @@ static int qpnp_revid_probe(struct platform_device *pdev) else fab_id = -EINVAL; - if (of_property_read_bool(pdev->dev.of_node, "qcom,tp-rev-valid")) - tp_rev = qpnp_read_byte(regmap, base + REVID_TP_REV); - else - tp_rev = -EINVAL; - revid_chip = devm_kzalloc(&pdev->dev, sizeof(struct revid_chip), GFP_KERNEL); if (!revid_chip) @@ -226,7 +243,6 @@ static int qpnp_revid_probe(struct platform_device *pdev) revid_chip->data.pmic_subtype = pmic_subtype; revid_chip->data.pmic_type = pmic_type; revid_chip->data.fab_id = fab_id; - revid_chip->data.tp_rev = tp_rev; if (pmic_subtype < ARRAY_SIZE(pmic_names)) revid_chip->data.pmic_name = pmic_names[pmic_subtype]; diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c index a9bcabfdb009195c931f7d10edf29e75942f56fa..a151d0c7a770d1359bda9a92e23a0bea8492e73f 100644 --- a/drivers/platform/msm/usb_bam.c +++ b/drivers/platform/msm/usb_bam.c @@ -103,6 +103,7 @@ struct usb_bam_sps_type { struct usb_bam_ctx_type { struct usb_bam_sps_type usb_bam_sps; struct resource *io_res; + void __iomem *regs; int irq; struct platform_device *usb_bam_pdev; struct workqueue_struct *usb_bam_wq; @@ -112,7 +113,6 @@ struct usb_bam_ctx_type { u32 inactivity_timer_ms; bool is_bam_inactivity; struct usb_bam_pipe_connect *usb_bam_connections; - struct msm_usb_bam_data *usb_bam_data; spinlock_t usb_bam_lock; }; @@ -126,13 +126,13 @@ static char *bam_enable_strings[MAX_BAMS] = { * CI_CTRL & DWC3_CTRL shouldn't be used simultaneously * since both share the same prod & cons rm resourses */ -static enum ipa_rm_resource_name ipa_rm_resource_prod[MAX_BAMS] = { +static enum ipa_client_type ipa_rm_resource_prod[MAX_BAMS] = { [CI_CTRL] = IPA_RM_RESOURCE_USB_PROD, [HSIC_CTRL] = IPA_RM_RESOURCE_HSIC_PROD, [DWC3_CTRL] = IPA_RM_RESOURCE_USB_PROD, }; -static enum ipa_rm_resource_name ipa_rm_resource_cons[MAX_BAMS] = { +static enum ipa_client_type ipa_rm_resource_cons[MAX_BAMS] = { [CI_CTRL] = IPA_RM_RESOURCE_USB_CONS, [HSIC_CTRL] = IPA_RM_RESOURCE_HSIC_CONS, [DWC3_CTRL] = IPA_RM_RESOURCE_USB_CONS, @@ -235,10 +235,10 @@ void msm_bam_set_hsic_host_dev(struct device *dev) if (dev) { /* Hold the device until allowing lpm */ info[HSIC_CTRL].in_lpm = false; - log_event_dbg("%s: Getting hsic device %pK\n", __func__, dev); + log_event_dbg("%s: Getting hsic device %p\n", __func__, dev); pm_runtime_get(dev); } else if (host_info[HSIC_CTRL].dev) { - log_event_dbg("%s: Try Putting hsic device %pK, lpm:%d\n", + log_event_dbg("%s: Try Putting hsic device %p, lpm:%d\n", __func__, host_info[HSIC_CTRL].dev, info[HSIC_CTRL].in_lpm); /* Just release previous device if not already done */ @@ -320,6 +320,8 @@ static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect) { int ret = 0; struct usb_bam_ctx_type *ctx = &msm_usb_bam[pipe_connect->bam_type]; + struct msm_usb_bam_platform_data *pdata = + ctx->usb_bam_pdev->dev.platform_data; struct sps_mem_buffer *data_buf = &(pipe_connect->data_mem_buf); struct sps_mem_buffer *desc_buf = &(pipe_connect->desc_mem_buf); @@ -358,7 +360,7 @@ static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect) } data_buf->phys_base = pipe_connect->data_fifo_base_offset + - ctx->usb_bam_data->usb_bam_fifo_baseaddr; + pdata->usb_bam_fifo_baseaddr; data_buf->size = pipe_connect->data_fifo_size; data_buf->base = ioremap(data_buf->phys_base, data_buf->size); if (!data_buf->base) { @@ -370,7 +372,7 @@ static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect) memset_io(data_buf->base, 0, data_buf->size); desc_buf->phys_base = pipe_connect->desc_fifo_base_offset + - ctx->usb_bam_data->usb_bam_fifo_baseaddr; + pdata->usb_bam_fifo_baseaddr; desc_buf->size = pipe_connect->desc_fifo_size; desc_buf->base = ioremap(desc_buf->phys_base, desc_buf->size); if (!desc_buf->base) { @@ -823,7 +825,7 @@ static bool _hsic_host_bam_resume_core(void) /* Exit from "full suspend" in case of hsic host */ if (host_info[HSIC_CTRL].dev && info[HSIC_CTRL].in_lpm) { - log_event_dbg("%s: Getting hsic device %pK\n", __func__, + log_event_dbg("%s: Getting hsic device %p\n", __func__, host_info[HSIC_CTRL].dev); pm_runtime_get(host_info[HSIC_CTRL].dev); info[HSIC_CTRL].in_lpm = false; @@ -837,7 +839,7 @@ static void _hsic_host_bam_suspend_core(void) log_event_dbg("%s: enter\n", __func__); if (host_info[HSIC_CTRL].dev && !info[HSIC_CTRL].in_lpm) { - log_event_dbg("%s: Putting hsic host device %pK\n", __func__, + log_event_dbg("%s: Putting hsic host device %p\n", __func__, host_info[HSIC_CTRL].dev); pm_runtime_put(host_info[HSIC_CTRL].dev); info[HSIC_CTRL].in_lpm = true; @@ -1068,6 +1070,7 @@ int usb_bam_connect(enum usb_ctrl cur_bam, int idx, u32 *bam_pipe_idx) struct usb_bam_pipe_connect *pipe_connect = &ctx->usb_bam_connections[idx]; struct device *bam_dev = &ctx->usb_bam_pdev->dev; + struct msm_usb_bam_platform_data *pdata = bam_dev->platform_data; enum usb_bam_mode cur_mode; if (pipe_connect->enabled) { @@ -1093,7 +1096,7 @@ int usb_bam_connect(enum usb_ctrl cur_bam, int idx, u32 *bam_pipe_idx) spin_lock(&ctx->usb_bam_lock); /* Check if BAM requires RESET before connect and reset of first pipe */ - if ((ctx->usb_bam_data->reset_on_connect == true) && + if ((pdata->reset_on_connect == true) && (ctx->pipes_enabled_per_bam == 0)) { spin_unlock(&ctx->usb_bam_lock); @@ -1593,6 +1596,8 @@ static int ss_usb_cons_release_resource(void) static void usb_bam_ipa_create_resources(enum usb_ctrl cur_bam) { struct usb_bam_ctx_type *ctx = &msm_usb_bam[cur_bam]; + struct msm_usb_bam_platform_data *pdata = + ctx->usb_bam_pdev->dev.platform_data; struct ipa_rm_create_params usb_prod_create_params; struct ipa_rm_create_params usb_cons_create_params; int ret; @@ -1601,8 +1606,7 @@ static void usb_bam_ipa_create_resources(enum usb_ctrl cur_bam) memset(&usb_prod_create_params, 0, sizeof(usb_prod_create_params)); usb_prod_create_params.name = ipa_rm_resource_prod[cur_bam]; usb_prod_create_params.reg_params.notify_cb = usb_prod_notify_cb; - usb_prod_create_params.reg_params.user_data - = &ctx->usb_bam_data->bam_type; + usb_prod_create_params.reg_params.user_data = &pdata->bam_type; usb_prod_create_params.floor_voltage = IPA_VOLTAGE_SVS; ret = ipa_rm_create_resource(&usb_prod_create_params); if (ret) { @@ -1625,22 +1629,6 @@ static void usb_bam_ipa_create_resources(enum usb_ctrl cur_bam) } } -static void usb_bam_ipa_delete_resources(enum usb_ctrl cur_bam) -{ - int ret; - - ret = ipa_rm_delete_resource(ipa_rm_resource_prod[cur_bam]); - if (ret) - log_event_err("%s: Failed to delete USB_PROD resource\n", - __func__); - - ret = ipa_rm_delete_resource(ipa_rm_resource_cons[cur_bam]); - if (ret) - log_event_err("%s: Failed to delete USB_CONS resource\n", - __func__); - -} - static void wait_for_prod_granted(enum usb_ctrl cur_bam) { int ret; @@ -1736,7 +1724,7 @@ static bool check_pipes_empty(enum usb_ctrl bam_type, u8 src_idx, u8 dst_idx) /* If we have any remaints in the pipes we don't go to sleep */ prod_pipe = ctx->usb_bam_sps.sps_pipes[src_idx]; cons_pipe = ctx->usb_bam_sps.sps_pipes[dst_idx]; - log_event_dbg("prod_pipe=%pK, cons_pipe=%pK\n", prod_pipe, cons_pipe); + log_event_dbg("prod_pipe=%p, cons_pipe=%p\n", prod_pipe, cons_pipe); if (!cons_pipe || (!prod_pipe && prod_pipe_connect->pipe_type == USB_BAM_PIPE_BAM2BAM)) { @@ -2103,7 +2091,7 @@ static bool msm_bam_host_lpm_ok(enum usb_ctrl bam_type) } /* HSIC host will go now to lpm */ - log_event_dbg("%s: vote for suspend hsic %pK\n", + log_event_dbg("%s: vote for suspend hsic %p\n", __func__, host_info[bam_type].dev); for (i = 0; i < ctx->max_connections; i++) { @@ -2148,14 +2136,16 @@ static int usb_bam_set_ipa_perf(enum usb_ctrl cur_bam, int ret; struct usb_bam_ctx_type *ctx = &msm_usb_bam[cur_bam]; struct ipa_rm_perf_profile ipa_rm_perf_prof; + struct msm_usb_bam_platform_data *pdata = + ctx->usb_bam_pdev->dev.platform_data; if (usb_connection_speed == USB_SPEED_SUPER) ipa_rm_perf_prof.max_supported_bandwidth_mbps = - ctx->usb_bam_data->max_mbps_superspeed; + pdata->max_mbps_superspeed; else /* Bam2Bam is supported only for SS and HS (HW limitation) */ ipa_rm_perf_prof.max_supported_bandwidth_mbps = - ctx->usb_bam_data->max_mbps_highspeed; + pdata->max_mbps_highspeed; /* * Having a max mbps property in dtsi file is a must @@ -2192,6 +2182,7 @@ int usb_bam_connect_ipa(enum usb_ctrl cur_bam, struct usb_bam_ctx_type *ctx = &msm_usb_bam[cur_bam]; struct usb_bam_pipe_connect *pipe_connect; struct device *bam_dev = &ctx->usb_bam_pdev->dev; + struct msm_usb_bam_platform_data *pdata = bam_dev->platform_data; int ret; bool bam2bam, is_dpl; @@ -2269,8 +2260,7 @@ int usb_bam_connect_ipa(enum usb_ctrl cur_bam, /* Check if BAM requires RESET before connect and reset first pipe */ spin_lock(&ctx->usb_bam_lock); - if (ctx->usb_bam_data->reset_on_connect && - !ctx->pipes_enabled_per_bam) { + if (pdata->reset_on_connect && !ctx->pipes_enabled_per_bam) { spin_unlock(&ctx->usb_bam_lock); if (cur_bam == CI_CTRL) @@ -2464,7 +2454,7 @@ static void usb_bam_work(struct work_struct *w) if (pipe_iter->bam_type == pipe_connect->bam_type && pipe_iter->dir == PEER_PERIPHERAL_TO_USB && pipe_iter->enabled) { - log_event_dbg("%s: Register wakeup on pipe %pK\n", + log_event_dbg("%s: Register wakeup on pipe %p\n", __func__, pipe_iter); __usb_bam_register_wake_cb( pipe_connect->bam_type, i, @@ -2620,6 +2610,8 @@ int usb_bam_disconnect_pipe(enum usb_ctrl bam_type, u8 idx) struct usb_bam_pipe_connect *pipe_connect; struct device *bam_dev = &ctx->usb_bam_pdev->dev; int ret; + struct msm_usb_bam_platform_data *pdata = + ctx->usb_bam_pdev->dev.platform_data; pipe_connect = &ctx->usb_bam_connections[idx]; @@ -2647,8 +2639,7 @@ int usb_bam_disconnect_pipe(enum usb_ctrl bam_type, u8 idx) log_event_dbg("%s: success disconnecting pipe %d\n", __func__, idx); - if (ctx->usb_bam_data->reset_on_disconnect - && !ctx->pipes_enabled_per_bam) { + if (pdata->reset_on_disconnect && !ctx->pipes_enabled_per_bam) { if (bam_type == CI_CTRL) msm_hw_bam_disable(1); @@ -2816,10 +2807,10 @@ static void usb_bam_sps_events(enum sps_callback_case sps_cb_case, void *user) } } -static struct msm_usb_bam_data *usb_bam_dt_to_data( +static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata( struct platform_device *pdev, u32 usb_addr) { - struct msm_usb_bam_data *usb_bam_data; + struct msm_usb_bam_platform_data *pdata; struct device_node *node = pdev->dev.of_node; int rc = 0; u8 i = 0; @@ -2828,10 +2819,10 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data( u32 threshold, max_connections = 0; static struct usb_bam_pipe_connect *usb_bam_connections; - usb_bam_data = devm_kzalloc(&pdev->dev, sizeof(*usb_bam_data), - GFP_KERNEL); - if (!usb_bam_data) + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { return NULL; + } rc = of_property_read_u32(node, "qcom,bam-type", &bam); if (rc) { @@ -2844,7 +2835,7 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data( __func__, bam); return NULL; } - usb_bam_data->bam_type = bam; + pdata->bam_type = bam; rc = of_property_read_u32(node, "qcom,bam-mode", &bam_mode); if (rc) { @@ -2854,49 +2845,49 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data( bam_mode = USB_BAM_DEVICE; } - usb_bam_data->reset_on_connect = of_property_read_bool(node, + pdata->reset_on_connect = of_property_read_bool(node, "qcom,reset-bam-on-connect"); - usb_bam_data->reset_on_disconnect = of_property_read_bool(node, + pdata->reset_on_disconnect = of_property_read_bool(node, "qcom,reset-bam-on-disconnect"); rc = of_property_read_u32(node, "qcom,usb-bam-num-pipes", - &usb_bam_data->usb_bam_num_pipes); + &pdata->usb_bam_num_pipes); if (rc) { log_event_err("Invalid usb bam num pipes property\n"); return NULL; } rc = of_property_read_u32(node, "qcom,usb-bam-max-mbps-highspeed", - &usb_bam_data->max_mbps_highspeed); + &pdata->max_mbps_highspeed); if (rc) - usb_bam_data->max_mbps_highspeed = 0; + pdata->max_mbps_highspeed = 0; rc = of_property_read_u32(node, "qcom,usb-bam-max-mbps-superspeed", - &usb_bam_data->max_mbps_superspeed); + &pdata->max_mbps_superspeed); if (rc) - usb_bam_data->max_mbps_superspeed = 0; + pdata->max_mbps_superspeed = 0; rc = of_property_read_u32(node, "qcom,usb-bam-fifo-baseaddr", &addr); if (rc) pr_debug("%s: Invalid usb base address property\n", __func__); else - usb_bam_data->usb_bam_fifo_baseaddr = addr; + pdata->usb_bam_fifo_baseaddr = addr; - usb_bam_data->ignore_core_reset_ack = of_property_read_bool(node, + pdata->ignore_core_reset_ack = of_property_read_bool(node, "qcom,ignore-core-reset-ack"); - usb_bam_data->disable_clk_gating = of_property_read_bool(node, + pdata->disable_clk_gating = of_property_read_bool(node, "qcom,disable-clk-gating"); rc = of_property_read_u32(node, "qcom,usb-bam-override-threshold", &threshold); if (rc) - usb_bam_data->override_threshold = USB_THRESHOLD; + pdata->override_threshold = USB_THRESHOLD; else - usb_bam_data->override_threshold = threshold; + pdata->override_threshold = threshold; - usb_bam_data->enable_hsusb_bam_on_boot = of_property_read_bool(node, + pdata->enable_hsusb_bam_on_boot = of_property_read_bool(node, "qcom,enable-hsusb-bam-on-boot"); for_each_child_of_node(pdev->dev.of_node, node) @@ -2932,7 +2923,7 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data( goto err; if (usb_bam_connections[i].mem_type == OCI_MEM) { - if (!usb_bam_data->usb_bam_fifo_baseaddr) { + if (!pdata->usb_bam_fifo_baseaddr) { log_event_err("%s: base address is missing\n", __func__); goto err; @@ -3016,7 +3007,7 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data( msm_usb_bam[bam].usb_bam_connections = usb_bam_connections; msm_usb_bam[bam].max_connections = max_connections; - return usb_bam_data; + return pdata; err: log_event_err("%s: failed\n", __func__); return NULL; @@ -3025,8 +3016,9 @@ err: static int usb_bam_init(struct platform_device *pdev) { int ret; - struct usb_bam_ctx_type *ctx = dev_get_drvdata(&pdev->dev); - enum usb_ctrl bam_type = ctx->usb_bam_data->bam_type; + struct msm_usb_bam_platform_data *pdata = pdev->dev.platform_data; + enum usb_ctrl bam_type = pdata->bam_type; + struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam_type]; struct sps_bam_props props; memset(&props, 0, sizeof(props)); @@ -3035,11 +3027,12 @@ static int usb_bam_init(struct platform_device *pdev) bam_enable_strings[bam_type]); props.phys_addr = ctx->io_res->start; + props.virt_addr = ctx->regs; props.virt_size = resource_size(ctx->io_res); props.irq = ctx->irq; - props.summing_threshold = ctx->usb_bam_data->override_threshold; - props.event_threshold = ctx->usb_bam_data->override_threshold; - props.num_pipes = ctx->usb_bam_data->usb_bam_num_pipes; + props.summing_threshold = pdata->override_threshold; + props.event_threshold = pdata->override_threshold; + props.num_pipes = pdata->usb_bam_num_pipes; props.callback = usb_bam_sps_events; props.user = bam_enable_strings[bam_type]; @@ -3047,10 +3040,10 @@ static int usb_bam_init(struct platform_device *pdev) * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs * Hence, let BAM to ignore acknowledge from USB while resetting PIPE */ - if (ctx->usb_bam_data->ignore_core_reset_ack && bam_type != DWC3_CTRL) + if (pdata->ignore_core_reset_ack && bam_type != DWC3_CTRL) props.options = SPS_BAM_NO_EXT_P_RST; - if (ctx->usb_bam_data->disable_clk_gating) + if (pdata->disable_clk_gating) props.options |= SPS_BAM_NO_LOCAL_CLK_GATING; /* @@ -3058,8 +3051,7 @@ static int usb_bam_init(struct platform_device *pdev) * starting peripheral controller to avoid switching USB core mode * from legacy to BAM with ongoing data transfers. */ - if (ctx->usb_bam_data->enable_hsusb_bam_on_boot - && bam_type == CI_CTRL) { + if (pdata->enable_hsusb_bam_on_boot && bam_type == CI_CTRL) { pr_debug("Register and enable HSUSB BAM\n"); props.options |= SPS_BAM_OPT_ENABLE_AT_BOOT; } @@ -3076,8 +3068,9 @@ static int usb_bam_init(struct platform_device *pdev) static int enable_usb_bam(struct platform_device *pdev) { int ret; - struct usb_bam_ctx_type *ctx = dev_get_drvdata(&pdev->dev); - enum usb_ctrl bam_type = ctx->usb_bam_data->bam_type; + struct msm_usb_bam_platform_data *pdata = pdev->dev.platform_data; + enum usb_ctrl bam_type = pdata->bam_type; + struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam_type]; ret = usb_bam_init(pdev); if (ret) { @@ -3144,19 +3137,14 @@ void usb_bam_register_panic_hdlr(void) &usb_bam_panic_blk); } -static void usb_bam_unregister_panic_hdlr(void) -{ - atomic_notifier_chain_unregister(&panic_notifier_list, - &usb_bam_panic_blk); -} - static int usb_bam_probe(struct platform_device *pdev) { int ret, i, irq; struct resource *io_res; + void __iomem *regs; enum usb_ctrl bam_type; struct usb_bam_ctx_type *ctx; - struct msm_usb_bam_data *usb_bam_data; + struct msm_usb_bam_platform_data *pdata; dev_dbg(&pdev->dev, "usb_bam_probe\n"); @@ -3172,19 +3160,25 @@ static int usb_bam_probe(struct platform_device *pdev) return irq; } + regs = devm_ioremap(&pdev->dev, io_res->start, resource_size(io_res)); + if (!regs) { + log_event_err("%s: ioremap failed\n", __func__); + return -ENOMEM; + } + /* specify BAM physical address to be filled in BAM connections */ - usb_bam_data = usb_bam_dt_to_data(pdev, io_res->start); - if (!usb_bam_data) + pdata = usb_bam_dt_to_pdata(pdev, io_res->start); + if (!pdata) return -EINVAL; - bam_type = usb_bam_data->bam_type; + pdev->dev.platform_data = pdata; + bam_type = pdata->bam_type; ctx = &msm_usb_bam[bam_type]; - dev_set_drvdata(&pdev->dev, ctx); ctx->usb_bam_pdev = pdev; ctx->irq = irq; + ctx->regs = regs; ctx->io_res = io_res; - ctx->usb_bam_data = usb_bam_data; for (i = 0; i < ctx->max_connections; i++) { ctx->usb_bam_connections[i].enabled = 0; @@ -3325,15 +3319,15 @@ EXPORT_SYMBOL(usb_bam_get_bam_type); bool msm_usb_bam_enable(enum usb_ctrl bam, bool bam_enable) { - struct msm_usb_bam_data *usb_bam_data; + struct msm_usb_bam_platform_data *pdata; struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam]; if (!ctx->usb_bam_pdev) return 0; - usb_bam_data = ctx->usb_bam_data; + pdata = ctx->usb_bam_pdev->dev.platform_data; if ((bam != CI_CTRL) || !(bam_enable || - usb_bam_data->enable_hsusb_bam_on_boot)) + pdata->enable_hsusb_bam_on_boot)) return 0; msm_hw_bam_disable(1); @@ -3415,11 +3409,10 @@ EXPORT_SYMBOL(msm_bam_hsic_lpm_ok); static int usb_bam_remove(struct platform_device *pdev) { - struct usb_bam_ctx_type *ctx = dev_get_drvdata(&pdev->dev); + struct msm_usb_bam_platform_data *pdata = pdev->dev.platform_data; + enum usb_ctrl bam_type = pdata->bam_type; + struct usb_bam_ctx_type *ctx = &msm_usb_bam[bam_type]; - usb_bam_ipa_delete_resources(ctx->usb_bam_data->bam_type); - usb_bam_unregister_panic_hdlr(); - sps_deregister_bam_device(ctx->h_bam); destroy_workqueue(ctx->usb_bam_wq); return 0; diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 09cc64b3b69584a798ac4281be8beed8ec9306d0..be3bc2f4edd4279d04749aba6db4f93aedf06c4f 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -807,7 +807,6 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) case 11: case 7: case 6: - case 1: ideapad_input_report(priv, vpc_bit); break; case 5: diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index b13cd074c52afc90c086bc16cc011b7adb0ac91f..296ab2854be4c509e55bdfdc172687dfed7e06ff 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -9,6 +9,11 @@ * * You may use this code as per GPL version 2 */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index a45a514908179346e6f0b511f34500b1993a9dc6..8d0a9f29829a436f4673d9466d6052d828748270 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -10,6 +10,11 @@ * * You may use this code as per GPL version 2 */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -297,12 +302,21 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(hw_current_max), POWER_SUPPLY_ATTR(real_type), POWER_SUPPLY_ATTR(pr_swap), - POWER_SUPPLY_ATTR(cc_step), - POWER_SUPPLY_ATTR(cc_step_sel), - POWER_SUPPLY_ATTR(sw_jeita_enabled), POWER_SUPPLY_ATTR(pd_voltage_max), POWER_SUPPLY_ATTR(pd_voltage_min), POWER_SUPPLY_ATTR(sdp_current_max), + POWER_SUPPLY_ATTR(skin_temp), + POWER_SUPPLY_ATTR(smart_charging_activation), + POWER_SUPPLY_ATTR(smart_charging_interruption), + POWER_SUPPLY_ATTR(smart_charging_status), + POWER_SUPPLY_ATTR(lrc_enable), + POWER_SUPPLY_ATTR(lrc_socmax), + POWER_SUPPLY_ATTR(lrc_socmin), + POWER_SUPPLY_ATTR(lrc_not_startup), + POWER_SUPPLY_ATTR(max_charge_current), + POWER_SUPPLY_ATTR(charge_full_raw), + POWER_SUPPLY_ATTR(time_to_cap_learning), + POWER_SUPPLY_ATTR(int_cld), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ @@ -310,6 +324,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(manufacturer), POWER_SUPPLY_ATTR(serial_number), POWER_SUPPLY_ATTR(battery_type), + POWER_SUPPLY_ATTR(charger_type), }; static struct attribute * diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c index 825c27e7a4c10f51c004b53a2f1480081e728154..43ad33ea234bd895ab99ffe863b795511886fb73 100644 --- a/drivers/power/qcom/msm-core.c +++ b/drivers/power/qcom/msm-core.c @@ -190,12 +190,10 @@ static void core_temp_notify(enum thermal_trip_type type, struct cpu_activity_info *cpu_node = (struct cpu_activity_info *) data; - temp /= scaling_factor; - trace_temp_notification(cpu_node->sensor_id, type, temp, cpu_node->temp); - cpu_node->temp = temp; + cpu_node->temp = temp / scaling_factor; complete(&sampling_completion); } diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 209263ccced72c4b3d26a6b03f459eff7bc45e2d..c0fe1a7e2788f7cf5d27b28df8fa5e6cc159b74e 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -294,6 +299,9 @@ static void msm_restart_prepare(const char *cmd) (cmd != NULL && cmd[0] != '\0')); } + if (in_panic) + need_warm_reset = true; + /* Hard reset the PMIC unless memory contents must be maintained. */ if (need_warm_reset) { qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET); @@ -301,7 +309,15 @@ static void msm_restart_prepare(const char *cmd) qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); } - if (cmd != NULL) { + if (in_panic) { + u32 prev_reason; + + prev_reason = __raw_readl(restart_reason); + if (prev_reason != 0xABADF00D) { + __raw_writel(0xC0DEDEAD, restart_reason); + qpnp_pon_set_restart_reason(PON_RESTART_REASON_KERNEL_PANIC); + } + } else if (cmd != NULL) { if (!strncmp(cmd, "bootloader", 10)) { qpnp_pon_set_restart_reason( PON_RESTART_REASON_BOOTLOADER); @@ -330,14 +346,32 @@ static void msm_restart_prepare(const char *cmd) unsigned long code; int ret; ret = kstrtoul(cmd + 4, 16, &code); - if (!ret) + if (!ret) { + if ((code & 0xff) == 'N') { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_SYSTEM); + } else if ((code & 0xff) == 'S') { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_XFL); + } else if ((code & 0xff) == 'F') { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_OEM_F); + } else if ((code & 0xff) == 'P') { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_OEM_P); + } __raw_writel(0x6f656d00 | (code & 0xff), restart_reason); + } } else if (!strncmp(cmd, "edl", 3)) { enable_emergency_dload_mode(); } else { __raw_writel(0x77665501, restart_reason); + qpnp_pon_set_restart_reason(PON_RESTART_REASON_UNKNOWN); } + } else { + __raw_writel(0x77665501, restart_reason); + qpnp_pon_set_restart_reason(PON_RESTART_REASON_UNKNOWN); } flush_cache_all(); @@ -389,7 +423,6 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) msm_trigger_wdog_bite(); #endif - scm_disable_sdi(); halt_spmi_pmic_arbiter(); deassert_ps_hold(); @@ -403,6 +436,7 @@ static void do_msm_poweroff(void) set_dload_mode(0); scm_disable_sdi(); qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN); + qpnp_pon_set_restart_reason(PON_RESTART_REASON_NONE); halt_spmi_pmic_arbiter(); deassert_ps_hold(); @@ -658,6 +692,7 @@ skip_sysfs_create: if (!download_mode) scm_disable_sdi(); #endif + return 0; err_restart_reason: diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index 47b2017386729361bad31b0593dd3f9a8d69d029..f93c3abc94e5653e2aae8ccd21f3c61d093eb7df 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -82,4 +82,18 @@ config QPNP_QNOVO module. It also allows userspace code to read diagnostics of voltage and current measured during certain phases of the pulses. +config QNS_SYSTEM + bool "Qnovo QNS wrapper implementation" + default n + help + Say Y here to enable support for QNS system. + QNS is a battery charging controller and it necessary to access a + kernel driver for a battery charging. + This adds sysfs interface which enables QNS daemon to access it. + +config SOMC_CHARGER_EXTENSION + bool "Charger driver extension" + help + Say Y here to enable extensional function of charger driver. + endmenu diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index 87ab2b24175f0d91305debe2478c5cb5b2616cbf..1a2339453d8b10a314e7f0186d56303f4d712cee 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_SMB1351_USB_CHARGER) += battery.o smb1351-charger.o pmic-voter.o obj-$(CONFIG_MSM_BCL_CTL) += msm_bcl.o obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o obj-$(CONFIG_BATTERY_BCL) += battery_current_limit.o -obj-$(CONFIG_QPNP_SMB2) += step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o +obj-$(CONFIG_QPNP_SMB2) += battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o obj-$(CONFIG_SMB138X_CHARGER) += battery.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o obj-$(CONFIG_QPNP_QNOVO) += battery.o qpnp-qnovo.o +obj-$(CONFIG_QNS_SYSTEM) += qns_system.o diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 5e8cc84fbfbf7495e33cf02df5a936424d3159b0..dff3e4a42e279df23f1ad9ef892602fa277e55be 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "QCOM-BATT: %s: " fmt, __func__ @@ -58,6 +63,9 @@ struct pl_data { struct delayed_work status_change_work; struct work_struct pl_disable_forever_work; struct delayed_work pl_taper_work; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + struct delayed_work voter_reelect_work; +#endif struct power_supply *main_psy; struct power_supply *pl_psy; struct power_supply *batt_psy; @@ -918,6 +926,24 @@ static void status_change_work(struct work_struct *work) handle_parallel_in_taper(chip); } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define PL_VOTER_REELECT_WORK_DELAY_MS 100 +static void voter_reelect_work(struct work_struct *work) +{ + struct pl_data *chip = container_of(work, struct pl_data, + voter_reelect_work.work); + if (is_main_available(chip) && + get_effective_result(chip->fcc_votable) > 0 && + get_effective_result(chip->fv_votable) > 0) { + rerun_election(chip->fcc_votable); + rerun_election(chip->fv_votable); + } else { + schedule_delayed_work(&chip->voter_reelect_work, + msecs_to_jiffies(PL_VOTER_REELECT_WORK_DELAY_MS)); + } +} + +#endif static int pl_notifier_call(struct notifier_block *nb, unsigned long ev, void *v) { @@ -985,9 +1011,16 @@ int qcom_batt_init(void) goto release_wakeup_source; } +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) chip->fv_votable = create_votable("FV", VOTE_MAX, pl_fv_vote_callback, chip); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chip->fv_votable = create_votable("FV", VOTE_MIN, + pl_fv_vote_callback, + chip); +#endif if (IS_ERR(chip->fv_votable)) { rc = PTR_ERR(chip->fv_votable); goto destroy_votable; @@ -1034,6 +1067,11 @@ int qcom_batt_init(void) INIT_DELAYED_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work); INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + INIT_DELAYED_WORK(&chip->voter_reelect_work, voter_reelect_work); + schedule_delayed_work(&chip->voter_reelect_work, + msecs_to_jiffies(PL_VOTER_REELECT_WORK_DELAY_MS)); +#endif rc = pl_register_notifier(chip); if (rc < 0) { diff --git a/drivers/power/supply/qcom/bcl_peripheral.c b/drivers/power/supply/qcom/bcl_peripheral.c index 2d237f27b062c470cb408dc38703e025faa2f6f3..d43f456aec5a45e43a7ebe262bc9d6420ee84318 100644 --- a/drivers/power/supply/qcom/bcl_peripheral.c +++ b/drivers/power/supply/qcom/bcl_peripheral.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__ @@ -76,7 +81,7 @@ #define BCL_8998_VBAT_SCALING 39000 #define BCL_8998_IBAT_SCALING 80000 #define BCL_VBAT_LOW_THRESHOLD 0x7 /* 3.1V */ -#define BCL_VBAT_TLOW_THRESHOLD 0x5 /* 2.9v */ +#define BCL_VBAT_TLOW_THRESHOLD 0x0 /* 2.4v */ #define BCL_IBAT_HIGH_THRESH_UA 4300000 #define BCL_LMH_CFG_VAL 0x3 #define BCL_CFG_VAL 0x81 diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 88dcdd8fd7beaf7ce8f961e3d41dfd2dd821d7f7..4e5cfa5493d7f0145285f628a59230e712d9cb1c 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __FG_CORE_H__ #define __FG_CORE_H__ @@ -49,7 +54,7 @@ #define SRAM_READ "fg_sram_read" #define SRAM_WRITE "fg_sram_write" #define PROFILE_LOAD "fg_profile_load" -#define TTF_PRIMING "fg_ttf_priming" +#define DELTA_SOC "fg_delta_soc" /* Delta BSOC irq votable reasons */ #define DELTA_BSOC_IRQ_VOTER "fg_delta_bsoc_irq" @@ -81,8 +86,6 @@ #define BATT_THERM_NUM_COEFFS 3 -#define MAX_CC_STEPS 20 - /* Debug flag definitions */ enum fg_debug_flag { FG_IRQ = BIT(0), /* Show interrupts */ @@ -94,6 +97,9 @@ enum fg_debug_flag { FG_BUS_READ = BIT(6), /* Show REGMAP reads */ FG_CAP_LEARN = BIT(7), /* Show capacity learning */ FG_TTF = BIT(8), /* Show time to full */ +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + FG_SOMC = BIT(15), +#endif }; /* SRAM access */ @@ -177,6 +183,12 @@ enum fg_sram_param_id { FG_SRAM_ESR_TIGHT_FILTER, FG_SRAM_ESR_BROAD_FILTER, FG_SRAM_SLOPE_LIMIT, +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + FG_SRAM_SOC_SYSTEM, + FG_SRAM_SOC_MONOTONIC, + FG_SRAM_SOC_CUTOFF, + FG_SRAM_SOC_FULL, +#endif FG_SRAM_MAX, }; @@ -230,11 +242,6 @@ enum esr_timer_config { NUM_ESR_TIMERS, }; -enum ttf_mode { - TTF_MODE_NORMAL = 0, - TTF_MODE_QNOVO, -}; - /* DT parameters for FG device */ struct fg_dt_props { bool force_load_profile; @@ -278,6 +285,11 @@ struct fg_dt_props { int ki_coeff_hi_dischg[KI_COEFF_SOC_LEVELS]; int slope_limit_coeffs[SLOPE_LIMIT_NUM_COEFFS]; u8 batt_therm_coeffs[BATT_THERM_NUM_COEFFS]; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int therm_coeff_c1; + int therm_coeff_c2; + int therm_coeff_c3; +#endif }; /* parameters from battery profile */ @@ -306,6 +318,17 @@ struct fg_cap_learning { int64_t final_cc_uah; int64_t learned_cc_uah; struct mutex lock; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int batt_soc_drop; + int cc_soc_drop; + int max_bsoc_during_active; + int max_ccsoc_during_active; + s64 max_bsoc_time_ms; + s64 start_time_ms; + s64 hold_time; + s64 total_time; + s64 learned_time_ms; +#endif }; struct fg_irq_info { @@ -316,31 +339,16 @@ struct fg_irq_info { }; struct fg_circ_buf { - int arr[10]; + int arr[20]; int size; int head; }; -struct fg_cc_step_data { - int arr[MAX_CC_STEPS]; - int sel; -}; - struct fg_pt { s32 x; s32 y; }; -struct ttf { - struct fg_circ_buf ibatt; - struct fg_circ_buf vbatt; - struct fg_cc_step_data cc_step; - struct mutex lock; - int mode; - int last_ttf; - s64 last_ms; -}; - static const struct fg_pt fg_ln_table[] = { { 1000, 0 }, { 2000, 693 }, @@ -370,6 +378,15 @@ static const struct fg_pt fg_tsmc_osc_table[] = { { 90, 444992 }, }; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define ORG_BATT_TYPE_SIZE 9 +#define BATT_TYPE_SIZE (ORG_BATT_TYPE_SIZE + 2) +#define BATT_TYPE_FIRST_HYPHEN 4 +#define BATT_TYPE_SECOND_HYPHEN 9 +#define BATT_TYPE_AGING_LEVEL 10 + +#endif + struct fg_chip { struct device *dev; struct pmic_revid_data *pmic_rev_id; @@ -380,7 +397,6 @@ struct fg_chip { struct power_supply *usb_psy; struct power_supply *dc_psy; struct power_supply *parallel_psy; - struct power_supply *pc_port_psy; struct iio_channel *batt_id_chan; struct iio_channel *die_temp_chan; struct fg_memif *sram; @@ -397,9 +413,9 @@ struct fg_chip { struct fg_cyc_ctr_data cyc_ctr; struct notifier_block nb; struct fg_cap_learning cl; - struct ttf ttf; struct mutex bus_lock; struct mutex sram_rw_lock; + struct mutex batt_avg_lock; struct mutex charge_full_lock; u32 batt_soc_base; u32 batt_info_base; @@ -412,14 +428,12 @@ struct fg_chip { int prev_charge_status; int charge_done; int charge_type; - int online_status; int last_soc; int last_batt_temp; int health; int maint_soc; int delta_soc; int last_msoc; - int last_recharge_volt_mv; int esr_timer_charging_default[NUM_ESR_TIMERS]; enum slope_limit_status slope_limit_sts; bool profile_available; @@ -438,8 +452,26 @@ struct fg_chip { struct completion soc_ready; struct delayed_work profile_load_work; struct work_struct status_change_work; - struct delayed_work ttf_work; + struct work_struct cycle_count_work; + struct delayed_work batt_avg_work; struct delayed_work sram_dump_work; + struct fg_circ_buf ibatt_circ_buf; + struct fg_circ_buf vbatt_circ_buf; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* Learning */ + int64_t charge_full_raw; + int rated_capacity; + int initial_capacity; + + /* Soft Charge */ + int batt_aging_level; + int saved_batt_aging_level; + char org_batt_type_str[ORG_BATT_TYPE_SIZE + 1]; + + /* Recharge */ + bool recharge_starting; + int recharge_voltage_mv; +#endif }; /* Debugfs data structures are below */ @@ -497,6 +529,5 @@ extern bool is_qnovo_en(struct fg_chip *chip); extern void fg_circ_buf_add(struct fg_circ_buf *, int); extern void fg_circ_buf_clr(struct fg_circ_buf *); extern int fg_circ_buf_avg(struct fg_circ_buf *, int *); -extern int fg_circ_buf_median(struct fg_circ_buf *, int *); extern int fg_lerp(const struct fg_pt *, size_t, s32, s32 *); #endif diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c index 0cb1dea7113b8e5790066f8afce099a1c385cf89..9635044e02a5bdca2fadd1e45facb27cc014bc6d 100644 --- a/drivers/power/supply/qcom/fg-util.c +++ b/drivers/power/supply/qcom/fg-util.c @@ -10,7 +10,6 @@ * GNU General Public License for more details. */ -#include #include "fg-core.h" void fg_circ_buf_add(struct fg_circ_buf *buf, int val) @@ -40,39 +39,6 @@ int fg_circ_buf_avg(struct fg_circ_buf *buf, int *avg) return 0; } -static int cmp_int(const void *a, const void *b) -{ - return *(int *)a - *(int *)b; -} - -int fg_circ_buf_median(struct fg_circ_buf *buf, int *median) -{ - int *temp; - - if (buf->size == 0) - return -ENODATA; - - if (buf->size == 1) { - *median = buf->arr[0]; - return 0; - } - - temp = kmalloc_array(buf->size, sizeof(*temp), GFP_KERNEL); - if (!temp) - return -ENOMEM; - - memcpy(temp, buf->arr, buf->size * sizeof(*temp)); - sort(temp, buf->size, sizeof(*temp), cmp_int, NULL); - - if (buf->size % 2) - *median = temp[buf->size / 2]; - else - *median = (temp[buf->size / 2 - 1] + temp[buf->size / 2]) / 2; - - kfree(temp); - return 0; -} - int fg_lerp(const struct fg_pt *pts, size_t tablesize, s32 input, s32 *output) { int i; diff --git a/drivers/power/supply/qcom/pmic-voter.c b/drivers/power/supply/qcom/pmic-voter.c index 3d0a718446086c343cd0f3e51fefa17db5591fa5..1a7b6d182e302cfa28c00116d2e17adae64f274f 100644 --- a/drivers/power/supply/qcom/pmic-voter.c +++ b/drivers/power/supply/qcom/pmic-voter.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -20,7 +25,9 @@ #include +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) #define NUM_MAX_CLIENTS 16 +#endif #define DEBUG_FORCE_CLIENT "DEBUG_FORCE_CLIENT" static DEFINE_SPINLOCK(votable_list_slock); @@ -438,14 +445,12 @@ out: int rerun_election(struct votable *votable) { int rc = 0; - int effective_result; lock_votable(votable); - effective_result = get_effective_result_locked(votable); if (votable->callback) rc = votable->callback(votable, - votable->data, - effective_result, + votable->data, + votable->effective_result, get_client_str(votable, votable->effective_client_id)); unlock_votable(votable); return rc; @@ -521,10 +526,11 @@ static int show_votable_clients(struct seq_file *m, void *data) lock_votable(votable); + seq_printf(m, "Votable %s:\n", votable->name); + seq_puts(m, "clients:\n"); for (i = 0; i < votable->num_clients; i++) { if (votable->client_strs[i]) { - seq_printf(m, "%s: %s:\t\t\ten=%d v=%d\n", - votable->name, + seq_printf(m, "%-15s:\t\ten=%d\t\tv=%d\n", votable->client_strs[i], votable->votes[i].enabled, votable->votes[i].value); @@ -543,11 +549,11 @@ static int show_votable_clients(struct seq_file *m, void *data) break; } + seq_printf(m, "type: %s\n", type_str); + seq_puts(m, "Effective:\n"); effective_client_str = get_effective_client_locked(votable); - seq_printf(m, "%s: effective=%s type=%s v=%d\n", - votable->name, + seq_printf(m, "%-15s:\t\tv=%d\n", effective_client_str ? effective_client_str : "none", - type_str, get_effective_result_locked(votable)); unlock_votable(votable); @@ -693,3 +699,65 @@ void destroy_votable(struct votable *votable) kfree(votable->name); kfree(votable); } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +ssize_t somc_output_voter_param(struct votable *votable, + char *buf, size_t size) +{ + int i; + int stored_size = 0; + char *print_format; + + memset(buf, '\0', size); + size--; + if (votable->type == VOTE_SET_ANY) { + for (i = 0; i < votable->num_clients + && votable->client_strs[i]; i++) { + if (!votable->votes[i].enabled) + continue; + + if (stored_size == 0) + print_format = "%s"; + else + print_format = "; %s"; + stored_size += scnprintf(buf + stored_size, + size - stored_size, print_format, + votable->client_strs[i]); + if (stored_size >= size) + break; + } + } else { + for (i = 0; i < votable->num_clients + && votable->client_strs[i]; i++) { + if (!votable->votes[i].enabled) + continue; + + if (stored_size == 0) + print_format = "%s:%d"; + else + print_format = "; %s:%d"; + stored_size += scnprintf(buf + stored_size, + size - stored_size, print_format, + votable->client_strs[i], + get_client_vote(votable, + votable->client_strs[i])); + if (stored_size >= size) + break; + } + } + if (stored_size < size) + stored_size += scnprintf(buf + stored_size, + size - stored_size, "\n"); + return stored_size; +} + +int somc_get_vote_clients(struct votable *votable, char *clients[]) +{ + int i; + int num_clients = 0; + for (i = 0; i < votable->num_clients; i++) { + if (votable->client_strs[i]) + clients[num_clients++] = votable->client_strs[i]; + } + return num_clients; +} +#endif diff --git a/drivers/power/supply/qcom/qns_system.c b/drivers/power/supply/qcom/qns_system.c new file mode 100644 index 0000000000000000000000000000000000000000..722110ceaa3d6a2cb86cbcf6125d807f51d34d24 --- /dev/null +++ b/drivers/power/supply/qcom/qns_system.c @@ -0,0 +1,608 @@ +/* + * qns_system.c version 1.2 + * Qnovo QNS wrapper implementation + * Copyright (C) 2014 Qnovo Corp + * Miro Zmrzli + * 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define QNS_USE_PM8941 +#define READ_CURRENT_SIGN (-1) +#define CHARGE_CURRENT_PROP POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT +#define CHARGE_VOLTAGE_PROP POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE + +#ifdef QNS_USE_PM8941 +#define IBATMANAME "battery" +#endif + +#define QNS_OK 0 +#define QNS_ERROR -1 + +//#define DEBUG + +static struct power_supply * ibat_psy = NULL; +static struct power_supply * battery_psy = NULL; +static struct power_supply * bms_psy = NULL; + +static struct alarm alarm; +static bool alarm_inited = false; +static int alarm_value = 0; + +static struct wake_lock wakelock; +static bool wakelock_inited = false; +static bool wakelock_held = false; + +static struct wake_lock charge_wakelock; +static bool charge_wakelock_inited = false; +static bool charge_wakelock_held = false; + +static int options = -1; + +static int qns_set_ibat(int ibatmA) +{ + union power_supply_propval propVal = {ibatmA*1000,}; + + static int prev_ibat_for_deblog = -1; + + if (ibatmA != prev_ibat_for_deblog) + pr_info("QNS: new charge current:%d mA\n", ibatmA); + else + pr_debug("QNS: new charge current:%d mA\n", ibatmA); + + if(ibat_psy == NULL) + { + ibat_psy = power_supply_get_by_name(IBATMANAME); + if(ibat_psy == NULL) + { + pr_info("QNS: ERROR: unable to get " IBATMANAME ". Can't set the current!"); + return QNS_ERROR; + } + } + if (ibatmA != prev_ibat_for_deblog) { + if(ibat_psy->desc->set_property(ibat_psy, + CHARGE_CURRENT_PROP, &propVal) != 0) + { + pr_info("QNS: ERROR: unable to set charging current! Does " IBATMANAME " have " + "POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT property?\n"); + return QNS_ERROR; + } + prev_ibat_for_deblog = ibatmA; + } + return QNS_OK; +} + +static int qns_set_vbat(int vbatmV) +{ +#if 0 + union power_supply_propval propVal = {vbatmV*1000,}; + + pr_info("QNS: new charge voltage:%d mV", vbatmV); + + if(ibat_psy == NULL) + { + ibat_psy = power_supply_get_by_name(IBATMANAME); + if(ibat_psy == NULL) + { + pr_info("QNS: ERROR: unable to get " IBATMANAME ". Can't set the voltage!"); + return QNS_ERROR; + } + } + if(ibat_psy->desc->set_property(ibat_psy, + CHARGE_VOLTAGE_PROP, &propVal) != 0) + { + pr_info("QNS: ERROR: unable to set charging voltage! Does " IBATMANAME " have " + "POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE property?"); + return QNS_ERROR; + } +#endif + return QNS_OK; +} + +static bool qns_is_charging(void) +{ + union power_supply_propval propVal = {0, }; + + if (battery_psy == NULL) + { + battery_psy = power_supply_get_by_name("battery"); + if(battery_psy == NULL) + { + pr_info("QNS: ERROR: unable to get \"battery\". Can't read charging state!"); + return false; + } + } + + if(battery_psy->desc->get_property(battery_psy, POWER_SUPPLY_PROP_STATUS, + &propVal) != 0) + { + pr_info("QNS: ERROR: unable to read charger properties! Does \"battery\" have " + "POWER_SUPPLY_PROP_STATUS property?"); + return false; + } + + return propVal.intval == POWER_SUPPLY_STATUS_CHARGING; +} + +static int qns_get_scvt(int *soc, int *c, int *v, int *tx10) +{ + /* + soc in % + c in ma + v in mv + t in 0.1 deg c + */ + union power_supply_propval ret = {0,}; + int retVal = QNS_OK; + + if (battery_psy == NULL) + { + battery_psy = power_supply_get_by_name("battery"); + if(battery_psy == NULL) + { + pr_info("QNS: ERROR: unable to get \"battery\". Can't read soc/c/v/t!"); + retVal = QNS_ERROR; + } + } + + if (battery_psy) + { + if(c != NULL) + { + if(battery_psy->desc->get_property(battery_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery property POWER_SUPPLY_PROP_CURRENT_NOW"); + *c = 0; + retVal = QNS_ERROR; + } + else + *c = READ_CURRENT_SIGN * ret.intval/1000; + } + + if(v != NULL) + { + if(battery_psy->desc->get_property(battery_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery property POWER_SUPPLY_PROP_VOLTAGE_NOW"); + *v = 0; + retVal = QNS_ERROR; + } + else + *v = ret.intval/1000; + } + + if(tx10 != NULL) + { + if(battery_psy->desc->get_property(battery_psy, + POWER_SUPPLY_PROP_TEMP, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery property POWER_SUPPLY_PROP_TEMP"); + *tx10 = 0; + retVal = QNS_ERROR; + } + else + *tx10 = ret.intval; + } + + if(soc != NULL) + { + if(battery_psy->desc->get_property(battery_psy, + POWER_SUPPLY_PROP_CAPACITY, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery property POWER_SUPPLY_PROP_CAPACITY"); + *soc = 0; + retVal = QNS_ERROR; + } + else + *soc = ret.intval; + } + } + else + { + pr_info("QNS: battery power supply is not registered yet."); + if(c != NULL) *c = 0; + if(v != NULL) *v = 4000; + if(tx10 != NULL) *tx10 = 250; + if(soc != NULL) *soc = 50; + retVal = QNS_ERROR; + } + return retVal; +} + +static int qns_get_fcc(int *fcc, int *design) +{ + union power_supply_propval ret = {0,}; + int retVal = QNS_OK; + + if (battery_psy == NULL) + { + battery_psy = power_supply_get_by_name("battery"); + if(battery_psy == NULL) + { + pr_info("QNS: ERROR: unable to get \"battery\". Can't read fcc/design!"); + retVal = QNS_ERROR; + } + } + + if (battery_psy) + { + if(fcc != NULL) + { + if(battery_psy->desc->get_property(battery_psy, + POWER_SUPPLY_PROP_CHARGE_FULL, &ret) != 0) + { + pr_info("QNS: ERRROR: unable to read battery POWER_SUPPLY_PROP_CHARGE_FULL property."); + *fcc = 0; + retVal = QNS_ERROR; + } + else + *fcc = ret.intval/1000; + } + if(design != NULL) + { + if(battery_psy->desc->get_property(battery_psy, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN property."); + *design = 0; + retVal = QNS_ERROR; + } + else + *design = ret.intval/1000; + } + } + return retVal; +} + +static int qns_get_battery_type(const char **battery_type) +{ + union power_supply_propval ret = {0,}; + int retVal = QNS_OK; + + if (bms_psy == NULL) + { + bms_psy = power_supply_get_by_name("bms"); + if(bms_psy == NULL) + { + pr_info("QNS: ERROR: unable to get \"bms\". Can't read battery_type!"); + *battery_type = "Unknown"; + retVal = QNS_ERROR; + } + } + + if (bms_psy) + { + if(battery_type != NULL) + { + if(bms_psy->desc->get_property(bms_psy, + POWER_SUPPLY_PROP_BATTERY_TYPE, &ret) != 0) + { + pr_info("QNS: ERRROR: unable to read battery POWER_SUPPLY_PROP_BATTERY_TYPE property."); + *battery_type = "Unknown"; + retVal = QNS_ERROR; + } + else + *battery_type = ret.strval; + } + } + return retVal; +} + +static ssize_t qns_param_show(struct class *dev, + struct class_attribute *attr, + char *buf); + +static ssize_t qns_param_store(struct class *dev, + struct class_attribute *attr, + const char *buf, + size_t count); + +enum +{ + IS_CHARGING, + CURRENT, + VOLTAGE, + TEMPERATURE, + FCC, + DESIGN, + SOC, + BATTERY_TYPE, + CHARGE_CURRENT, + CHARGE_VOLTAGE, + ALARM, + OPTIONS, +}; + +static struct class_attribute qns_attrs[] = { + __ATTR(charging_state, S_IRUGO, qns_param_show, NULL), + __ATTR(current_now, S_IRUGO, qns_param_show, NULL), + __ATTR(voltage, S_IRUGO, qns_param_show, NULL), + __ATTR(temp, S_IRUGO, qns_param_show, NULL), + __ATTR(fcc, S_IRUGO, qns_param_show, NULL), + __ATTR(design, S_IRUGO, qns_param_show, NULL), + __ATTR(soc, S_IRUGO, qns_param_show, NULL), +#ifdef DEBUG + __ATTR(battery_type, S_IWUSR | S_IRUGO, qns_param_show, qns_param_store), +#else + __ATTR(battery_type, S_IRUGO, qns_param_show, NULL), +#endif + __ATTR(charge_current, S_IWUSR, NULL, qns_param_store), + __ATTR(charge_voltage, S_IWUSR, NULL, qns_param_store), + __ATTR(alarm, S_IWUSR | S_IRUGO, qns_param_show, qns_param_store), + __ATTR(options, S_IWUSR | S_IRUGO, qns_param_show, qns_param_store), + __ATTR_NULL, +}; + +static enum alarmtimer_restart qns_alarm_handler(struct alarm * alarm, ktime_t now) +{ + pr_info("QNS: ALARM! System wakeup!"); + wake_lock(&wakelock); + wakelock_held = true; + alarm_value = 1; + return ALARMTIMER_NORESTART; +} + +#ifdef DEBUG +char battid[32] = {'1','2','9','8','-','9','2','3','9'}; +#endif + +static ssize_t qns_param_show(struct class *dev, + struct class_attribute *attr, + char *buf) +{ + ssize_t size = 0; + const ptrdiff_t off = attr - qns_attrs; + static int t, c, v; + const char *battery_type; + + switch(off) + { + case IS_CHARGING: + size = scnprintf(buf, PAGE_SIZE, "%d\n", qns_is_charging() ? 1 : 0); + break; + case CURRENT: + qns_get_scvt(NULL, &c, &v, NULL); + size = scnprintf(buf, PAGE_SIZE, "%d\n", c); + break; + case VOLTAGE: + size = scnprintf(buf, PAGE_SIZE, "%d\n", v); + break; + case TEMPERATURE: + qns_get_scvt(NULL, NULL, NULL, &t); + size = scnprintf(buf, PAGE_SIZE, "%d\n", t); + break; + case FCC: + qns_get_fcc(&t, NULL); + size = scnprintf(buf, PAGE_SIZE, "%d\n", t); + break; + case DESIGN: + qns_get_fcc(NULL, &t); + size = scnprintf(buf, PAGE_SIZE, "%d\n", t); + break; + case SOC: + qns_get_scvt(&t, NULL, NULL, NULL); + size = scnprintf(buf, PAGE_SIZE, "%d\n", t); + break; + case ALARM: + size = scnprintf(buf, PAGE_SIZE, "%d\n", alarm_value); + break; + case OPTIONS: + size = scnprintf(buf, PAGE_SIZE, "%d\n", options); + break; + case BATTERY_TYPE: +#ifdef DEBUG + size = scnprintf(buf, PAGE_SIZE, "%s\n", battid); +#else + qns_get_battery_type(&battery_type); + size = scnprintf(buf, PAGE_SIZE, "%s\n", battery_type); +#endif + break; + } + + return size; +} + +enum alarm_values +{ + CHARGE_WAKELOCK = -4, + CHARGE_WAKELOCK_RELEASE = -3, + HANDLED = -2, + CANCEL = -1, + IMMEDIATE = 0, +}; + +static ssize_t qns_param_store(struct class *dev, + struct class_attribute *attr, + const char *buf, + size_t count) +{ + int val, ret = -EINVAL; + ktime_t next_alarm; + const ptrdiff_t off = attr - qns_attrs; + + switch(off) + { + case CHARGE_CURRENT: + ret = kstrtoint(buf, 10, &val); + if (!ret && (val > 0)) + { + qns_set_ibat(val); + return count; + } + else + return -EINVAL; + break; + + case CHARGE_VOLTAGE: + ret = kstrtoint(buf, 10, &val); + if (!ret && (val > 0)) + { + qns_set_vbat(val); + return count; + } + else + return -EINVAL; + break; + + case ALARM: + ret = kstrtoint(buf, 10, &val); + + if(!wakelock_inited) + { + wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "QnovoQNS"); + wakelock_inited = true; + } + + if(!charge_wakelock_inited) + { + wake_lock_init(&charge_wakelock, WAKE_LOCK_SUSPEND, "QnovoQNS"); + charge_wakelock_inited = true; + } + + if (!ret) + { + if(val == CHARGE_WAKELOCK) + { + if(!charge_wakelock_held) + { + pr_info("QNS: Alarm: acquiring charge_wakelock via CHARGE_WAKELOCK"); + + wake_lock(&charge_wakelock); + charge_wakelock_held = true; + } + } + else if(val == CHARGE_WAKELOCK_RELEASE) + { + if(charge_wakelock_held) + { + pr_info("QNS: Alarm: releasing charge_wakelock via CHARGE_WAKELOCK_RELEASE"); + + wake_unlock(&charge_wakelock); + charge_wakelock_held = false; + } + } + else if(val == HANDLED) + { + if(wakelock_held) + { + pr_info("QNS: Alarm: releasing wakelock via HANDLED"); + wake_unlock(&wakelock); + } + alarm_value = 0; + wakelock_held = false; + } + else if(val == CANCEL) + { + if(alarm_inited) + { + alarm_cancel(&alarm); + } + alarm_value = 0; + if(wakelock_held) + { + pr_info("QNS: Alarm: releasing wakelock via CANCEL"); + wake_unlock(&wakelock); + } + wakelock_held = false; + } + else if(val == IMMEDIATE) + { + if(!wakelock_held) + { + pr_info("QNS: Alarm: acquiring wakelock via IMMEDIATE"); + + wake_lock(&wakelock); + wakelock_held = true; + } + } + else if(val > 0) + { + if(!alarm_inited) + { + alarm_init(&alarm, ALARM_REALTIME, qns_alarm_handler); + alarm_inited = true; + } + + next_alarm = ktime_set(val, 0); + alarm_start_relative(&alarm, next_alarm); + + if(wakelock_held) + { + pr_info("QNS: Alarm: releasing wakelock via alarm>0"); + + wake_unlock(&wakelock); + } + alarm_value = 0; + wakelock_held = false; + } + } + break; + + case OPTIONS: + ret = kstrtoint(buf, 10, &val); + if (!ret && (val >= 0)) + options = val; + else + return -EINVAL; + break; +#ifdef DEBUG + case BATTERY_TYPE: + strcpy(battid , buf); + pr_info("QNS: received '%s'", battid); + val = strlen(battid); + if (val > 0 && val < 32) + battid[val-1] = 0; + pr_info("QNS: new id '%s'", battid); + break; +#endif + } + return count; +} + +static struct class qns_class = +{ + .name = "qns", + .owner = THIS_MODULE, + .class_attrs = qns_attrs +}; + +MODULE_AUTHOR("Miro Zmrzli "); +MODULE_DESCRIPTION("QNS System Driver v2"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("QNS"); + +static int qnovo_qns_init(void) +{ + class_register(&qns_class); + return 0; +} +static void qnovo_qns_exit(void) +{ + class_unregister(&qns_class); +} + +module_init(qnovo_qns_init); +module_exit(qnovo_qns_exit); diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 361efd4fbbbd23dbf6396e1b40edf2b9ad86cff9..d0fda161ee01cbc651636648d5f99449806c471f 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -9,10 +9,18 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "FG: %s: " fmt, __func__ #include +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#include +#endif #include #include #include @@ -29,12 +37,23 @@ #define FG_BATT_SOC_PMI8998 0x10 #define FG_BATT_INFO_PMI8998 0x11 #define FG_MEM_INFO_PMI8998 0x0D - +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define FG_ESR_CURRENT_THR_VALUE 0x1C +#define KI_COEFF_CUTOFF_VOLT_VALUE 0x18 +#define ESR_VCTIBTRSLWEN_MASK 0xC0 +#define ESR_VCTIBTRSLWEN_VALUE 0xC0 +#define SAT_CC_CLR_AUTO_MASK 0x08 +#define SAT_CC_CLR_AUTO_VALUE 0x08 +#endif /* SRAM address and offset in ascending order */ #define ESR_PULSE_THRESH_WORD 2 #define ESR_PULSE_THRESH_OFFSET 3 #define SLOPE_LIMIT_WORD 3 #define SLOPE_LIMIT_OFFSET 0 +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define ESR_CURRENT_THR_WORD 2 +#define ESR_CURRENT_THR_OFFSET 3 +#endif #define CUTOFF_VOLT_WORD 5 #define CUTOFF_VOLT_OFFSET 0 #define SYS_TERM_CURR_WORD 6 @@ -55,6 +74,10 @@ #define KI_COEFF_LOW_DISCHG_OFFSET 2 #define KI_COEFF_FULL_SOC_WORD 12 #define KI_COEFF_FULL_SOC_OFFSET 2 +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define KI_COEFF_CUTOFF_VOLT_WORD 12 +#define KI_COEFF_CUTOFF_VOLT_OFFSET 1 +#endif #define DELTA_MSOC_THR_WORD 12 #define DELTA_MSOC_THR_OFFSET 3 #define DELTA_BSOC_THR_WORD 13 @@ -75,8 +98,12 @@ #define ESR_TIMER_CHG_MAX_OFFSET 0 #define ESR_TIMER_CHG_INIT_WORD 18 #define ESR_TIMER_CHG_INIT_OFFSET 2 -#define ESR_EXTRACTION_ENABLE_WORD 19 -#define ESR_EXTRACTION_ENABLE_OFFSET 0 +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define SAT_CC_CLR_AUTO_WORD 19 +#define SAT_CC_CLR_AUTO_OFFSET 0 +#define ESR_VCTIBTRSLWEN_WORD 19 +#define ESR_VCTIBTRSLWEN_OFFSET 1 +#endif #define PROFILE_LOAD_WORD 24 #define PROFILE_LOAD_OFFSET 0 #define ESR_RSLOW_DISCHG_WORD 34 @@ -87,6 +114,10 @@ #define NOM_CAP_OFFSET 0 #define ACT_BATT_CAP_BKUP_WORD 74 #define ACT_BATT_CAP_BKUP_OFFSET 0 +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define BATT_AGING_LEVEL_WORD 74 +#define BATT_AGING_LEVEL_OFFSET 3 +#endif #define CYCLE_COUNT_WORD 75 #define CYCLE_COUNT_OFFSET 0 #define PROFILE_INTEGRITY_WORD 79 @@ -94,8 +125,16 @@ #define PROFILE_INTEGRITY_OFFSET 3 #define BATT_SOC_WORD 91 #define BATT_SOC_OFFSET 0 +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define SOC_CUTOFF_WORD 93 +#define SOC_CUTOFF_OFFSET 0 +#endif #define FULL_SOC_WORD 93 #define FULL_SOC_OFFSET 2 +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define SOC_SYSTEM_WORD 94 +#define SOC_SYSTEM_OFFSET 0 +#endif #define MONOTONIC_SOC_WORD 94 #define MONOTONIC_SOC_OFFSET 2 #define CC_SOC_WORD 95 @@ -208,8 +247,20 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = { 1000000, 122070, 0, fg_encode_current, NULL), PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1, 100000, 390625, 0, fg_encode_current, NULL), +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* + * Changed the value of numrtr from 2048 to 1024. By this change, + * the value of DELTA_MSOC threshold turns into 0x0A(0.48828%) + * from 0x14(0.97656%). In addition, the value of DELTA_MSOC + * threshold is calculated in following macro. + * DIV_ROUND_CLOSEST(qcom,fg-delta-soc-thr * numrtr), denmtr) + */ + PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1, + 1024, 100, 0, fg_encode_default, NULL), +#else PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), +#endif PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET, @@ -241,6 +292,16 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = { 1, 512, 1000000, 0, fg_encode_default, NULL), PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000, 0, fg_encode_default, NULL), +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + PARAM(SOC_SYSTEM, SOC_SYSTEM_WORD, SOC_SYSTEM_OFFSET, 2, 1, + 1, 0, NULL, fg_decode_default), + PARAM(SOC_MONOTONIC, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET, 2, 1, + 1, 0, NULL, fg_decode_default), + PARAM(SOC_CUTOFF, SOC_CUTOFF_WORD, SOC_CUTOFF_OFFSET, 2, 1, + 1, 0, NULL, fg_decode_default), + PARAM(SOC_FULL, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, + 1, 0, NULL, fg_decode_default), +#endif }; static struct fg_sram_param pmi8998_v2_sram_params[] = { @@ -284,8 +345,20 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = { PARAM(CHG_TERM_BASE_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_BASE_CURR_v2_OFFSET, 1, 1024, 1000, 0, fg_encode_current, NULL), +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* + * Changed the value of numrtr from 2048 to 1024. By this change, + * the value of DELTA_MSOC threshold turns into 0x0A(0.48828%) + * from 0x14(0.97656%). In addition, the value of DELTA_MSOC + * threshold is calculated in following macro. + * DIV_ROUND_CLOSEST(qcom,fg-delta-soc-thr * numrtr), denmtr) + */ + PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET, + 1, 1024, 100, 0, fg_encode_default, NULL), +#else PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), +#endif PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET, 1, 2048, 100, 0, fg_encode_default, NULL), PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD, @@ -321,6 +394,16 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = { 1, 512, 1000000, 0, fg_encode_default, NULL), PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000, 0, fg_encode_default, NULL), +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + PARAM(SOC_SYSTEM, SOC_SYSTEM_WORD, SOC_SYSTEM_OFFSET, 2, 1, + 1, 0, NULL, fg_decode_default), + PARAM(SOC_MONOTONIC, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET, 2, 1, + 1, 0, NULL, fg_decode_default), + PARAM(SOC_CUTOFF, SOC_CUTOFF_WORD, SOC_CUTOFF_OFFSET, 2, 1, + 1, 0, NULL, fg_decode_default), + PARAM(SOC_FULL, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, + 1, 0, NULL, fg_decode_default), +#endif }; static struct fg_alg_flag pmi8998_v1_alg_flags[] = { @@ -384,7 +467,13 @@ static struct fg_alg_flag pmi8998_v2_alg_flags[] = { }, }; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) static int fg_gen3_debug_mask; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +static int fg_gen3_debug_mask = + FG_SOMC; +#endif module_param_named( debug_mask, fg_gen3_debug_mask, int, S_IRUSR | S_IWUSR ); @@ -573,11 +662,19 @@ static int fg_get_charge_counter(struct fg_chip *chip, int *val) } *val = div_s64(cc_soc * chip->cl.learned_cc_uah, CC_SOC_30BIT); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (*val < 1) + *val = 1; + +#endif return 0; } #define BATT_TEMP_NUMR 1 #define BATT_TEMP_DENR 1 +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define CONV_BATT_TEMP_DEGC_FROM_LSB(t) (t * 25 / 10 - 2730) +#endif static int fg_get_battery_temp(struct fg_chip *chip, int *val) { int rc = 0, temp; @@ -592,11 +689,17 @@ static int fg_get_battery_temp(struct fg_chip *chip, int *val) temp = ((buf[1] & BATT_TEMP_MSB_MASK) << 8) | (buf[0] & BATT_TEMP_LSB_MASK); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) temp = DIV_ROUND_CLOSEST(temp, 4); /* Value is in Kelvin; Convert it to deciDegC */ temp = (temp - 273) * 10; *val = temp; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* Value is in Kelvin; Convert it to deciDegC with keeping accuracy */ + *val = CONV_BATT_TEMP_DEGC_FROM_LSB(temp); +#endif return 0; } @@ -672,6 +775,20 @@ static int fg_get_battery_voltage(struct fg_chip *chip, int *val) return 0; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +static int fg_get_vbatt_predict(struct fg_chip *chip, int *val) +{ + int rc; + + rc = fg_get_sram_prop(chip, FG_SRAM_VOLTAGE_PRED, val); + if (rc < 0) { + pr_err("Error in getting VOLTAGE_PRED, rc=%d\n", rc); + return rc; + } + return 0; +} + +#endif #define MAX_TRIES_SOC 5 static int fg_get_msoc_raw(struct fg_chip *chip, int *val) { @@ -804,6 +921,9 @@ static bool is_debug_batt_id(struct fg_chip *chip) #define DEBUG_BATT_SOC 67 #define BATT_MISS_SOC 50 +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define UNKNOWN_BATT_SOC 20 +#endif #define EMPTY_SOC 0 static int fg_get_prop_capacity(struct fg_chip *chip, int *val) { @@ -815,7 +935,15 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val) } if (chip->fg_restarting) { +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) *val = chip->last_soc; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chip->last_soc) + *val = chip->last_soc; + else + *val = UNKNOWN_BATT_SOC; +#endif return 0; } @@ -829,6 +957,21 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val) return 0; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (!chip->profile_available) { + *val = UNKNOWN_BATT_SOC; + return 0; + } + + if (!chip->profile_loaded) { + if (chip->last_soc) + *val = chip->last_soc; + else + *val = UNKNOWN_BATT_SOC; + return 0; + } + +#endif if (chip->charge_full) { *val = FULL_CAPACITY; return 0; @@ -854,10 +997,24 @@ static const char *fg_get_battery_type(struct fg_chip *chip) return MISSING_BATT_TYPE; if (chip->bp.batt_type_str) { +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (chip->profile_loaded) return chip->bp.batt_type_str; else if (chip->profile_available) return LOADING_BATT_TYPE; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chip->profile_loaded) { + if (strlen(chip->org_batt_type_str) == + ORG_BATT_TYPE_SIZE) + return chip->org_batt_type_str; + else + return chip->bp.batt_type_str; + + } else { + return LOADING_BATT_TYPE; + } +#endif } return DEFAULT_BATT_TYPE; @@ -910,6 +1067,151 @@ out: return rc; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +static int fg_somc_batterydata_read_batt_ids(const struct device_node *np, + struct batt_ids *batt_ids) +{ + struct property *prop; + const __be32 *data; + int num, i; + int *id_kohm = batt_ids->kohm; + + prop = of_find_property(np, "qcom,batt-id-kohm", NULL); + if (!prop) { + pr_err("%s: No battery id resistor found\n", np->name); + return -EINVAL; + } else if (!prop->value) { + pr_err("%s: No battery id resistor value found, np->name\n", + np->name); + return -ENODATA; + } else if (prop->length > MAX_BATT_ID_NUM * sizeof(__be32)) { + pr_err("%s: Too many battery id resistors\n", np->name); + return -EINVAL; + } + + num = prop->length / sizeof(__be32); + batt_ids->num = num; + data = prop->value; + for (i = 0; i < num; i++) + *id_kohm++ = be32_to_cpup(data++); + + return 0; +} + +int fg_somc_check_battery_type(char *battery_type) +{ + int i; + int rc; + int aging_level; + + if (battery_type == NULL || strlen(battery_type) != BATT_TYPE_SIZE) + return -EINVAL; + + for (i = 0; i < BATT_TYPE_SIZE; i++) { + if (i == BATT_TYPE_FIRST_HYPHEN || + i == BATT_TYPE_SECOND_HYPHEN) { + if (battery_type[i] != '-') + break; + } else { + if (!isdigit(battery_type[i])) + break; + } + } + + if (i < BATT_TYPE_SIZE) + return -EINVAL; + + rc = kstrtoint(&battery_type[BATT_TYPE_AGING_LEVEL], 10, &aging_level); + if (rc < 0) + return -EINVAL; + + return aging_level; +} + +struct device_node *fg_somc_battery_data_get_best_profile( + const struct device_node *batterydata_container_node, + int batt_id_kohm, int batt_aging_level) +{ + struct batt_ids batt_ids; + struct device_node *node; + struct device_node *best_node = NULL; + char *battery_type = NULL; + char *best_node_battery_type = NULL; + int delta = 0; + int best_delta = 0; + int best_id_kohm = 0; + int i = 0; + int rc = 0; + int limit = 0; + int id_range_pct; + int matching_batt_aging_level; + bool in_range = false; + + /*read battery id range percentage for best profile*/ + rc = of_property_read_u32(batterydata_container_node, + "qcom,batt-id-range-pct", &id_range_pct); + if (rc) { + if (rc == -EINVAL) { + id_range_pct = 0; + } else { + pr_err("failed to read battery id range\n"); + return NULL; + } + } + /* + * Find the battery data with a battery id resistor closest to this one + */ + for_each_child_of_node(batterydata_container_node, node) { + rc = of_property_read_string(node, "qcom,battery-type", + (const char **)&battery_type); + if (!rc) { + matching_batt_aging_level = + fg_somc_check_battery_type(battery_type); + } else { + matching_batt_aging_level = -1; + battery_type = NULL; + } + + if (matching_batt_aging_level >= 0 && + matching_batt_aging_level != batt_aging_level) + continue; + + rc = fg_somc_batterydata_read_batt_ids(node, &batt_ids); + if (rc) + continue; + for (i = 0; i < batt_ids.num; i++) { + delta = abs(batt_ids.kohm[i] - batt_id_kohm); + limit = (batt_ids.kohm[i] * id_range_pct) / 100; + in_range = (delta <= limit); + + /* + * Check if the delta is the lowest one + * and also if the limits are in range + * before selecting the best node. + */ + if (in_range && (delta < best_delta || !best_node)) { + best_node = node; + best_node_battery_type = battery_type; + best_delta = delta; + best_id_kohm = batt_ids.kohm[i]; + } + } + } + + if (best_node == NULL) { + pr_err("No battery data found\n"); + return best_node; + } + + if (best_node_battery_type) + pr_info("%s found\n", best_node_battery_type); + else + pr_info("%s found\n", best_node->name); + + return best_node; +} + +#endif static int fg_get_batt_profile(struct fg_chip *chip) { struct device_node *node = chip->dev->of_node; @@ -923,8 +1225,14 @@ static int fg_get_batt_profile(struct fg_chip *chip) return -ENXIO; } +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) profile_node = of_batterydata_get_best_profile(batt_node, chip->batt_id_ohms / 1000, NULL); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + profile_node = fg_somc_battery_data_get_best_profile(batt_node, + chip->batt_id_ohms / 1000, chip->batt_aging_level); +#endif if (IS_ERR(profile_node)) return PTR_ERR(profile_node); @@ -940,6 +1248,13 @@ static int fg_get_batt_profile(struct fg_chip *chip) return rc; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + memset(chip->org_batt_type_str, '\0', ORG_BATT_TYPE_SIZE + 1); + if (fg_somc_check_battery_type((char *)chip->bp.batt_type_str) >= 0) + strlcpy(chip->org_batt_type_str, + chip->bp.batt_type_str, ORG_BATT_TYPE_SIZE + 1); + +#endif rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv", &chip->bp.float_volt_uv); if (rc < 0) { @@ -1173,42 +1488,6 @@ static bool batt_psy_initialized(struct fg_chip *chip) return true; } -static bool usb_psy_initialized(struct fg_chip *chip) -{ - if (chip->usb_psy) - return true; - - chip->usb_psy = power_supply_get_by_name("usb"); - if (!chip->usb_psy) - return false; - - return true; -} - -static bool pc_port_psy_initialized(struct fg_chip *chip) -{ - if (chip->pc_port_psy) - return true; - - chip->pc_port_psy = power_supply_get_by_name("pc_port"); - if (!chip->pc_port_psy) - return false; - - return true; -} - -static bool dc_psy_initialized(struct fg_chip *chip) -{ - if (chip->dc_psy) - return true; - - chip->dc_psy = power_supply_get_by_name("dc"); - if (!chip->dc_psy) - return false; - - return true; -} - static bool is_parallel_charger_available(struct fg_chip *chip) { if (!chip->parallel_psy) @@ -1315,24 +1594,27 @@ static bool is_temp_valid_cap_learning(struct fg_chip *chip) return true; } -#define QNOVO_CL_SKEW_DECIPCT -30 static void fg_cap_learning_post_process(struct fg_chip *chip) { int64_t max_inc_val, min_dec_val, old_cap; int rc; - if (is_qnovo_en(chip)) { - fg_dbg(chip, FG_CAP_LEARN, "applying skew %d on current learnt capacity %lld\n", - QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah); - chip->cl.final_cc_uah = chip->cl.final_cc_uah * - (1000 + QNOVO_CL_SKEW_DECIPCT); - do_div(chip->cl.final_cc_uah, 1000); - } - +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) max_inc_val = chip->cl.learned_cc_uah * (1000 + chip->dt.cl_max_cap_inc); do_div(max_inc_val, 1000); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (!chip->dt.cl_max_cap_inc) { + max_inc_val = chip->cl.nom_cap_uah; + } else { + max_inc_val = chip->cl.learned_cc_uah + * (1000 + chip->dt.cl_max_cap_inc); + do_div(max_inc_val, 1000); + } + +#endif min_dec_val = chip->cl.learned_cc_uah * (1000 - chip->dt.cl_max_cap_dec); do_div(min_dec_val, 1000); @@ -1372,14 +1654,30 @@ static void fg_cap_learning_post_process(struct fg_chip *chip) if (rc < 0) pr_err("Error in saving learned_cc_uah, rc=%d\n", rc); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) fg_dbg(chip, FG_CAP_LEARN, "final cc_uah = %lld, learned capacity %lld -> %lld uah\n", chip->cl.final_cc_uah, old_cap, chip->cl.learned_cc_uah); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chip->charge_full_raw = chip->cl.final_cc_uah; + chip->cl.learned_time_ms = ktime_to_ms(ktime_get_boottime()); + fg_dbg(chip, FG_SOMC, + "final cc_uah = %lld, learned capacity %lld -> %lld, time=%lld\n", + chip->cl.final_cc_uah, old_cap, + chip->cl.learned_cc_uah, chip->cl.learned_time_ms); +#endif } static int fg_cap_learning_process_full_data(struct fg_chip *chip) { +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) int rc, cc_soc_sw, cc_soc_delta_pct; int64_t delta_cc_uah; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int rc, cc_soc_sw; + int64_t cc_soc_delta_100pct, delta_cc_uah; +#endif rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw); if (rc < 0) { @@ -1387,6 +1685,7 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip) return rc; } +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) cc_soc_delta_pct = div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100, CC_SOC_30BIT); @@ -1399,9 +1698,24 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip) delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct, 100); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + cc_soc_delta_100pct = DIV_ROUND_CLOSEST( + (s64)(abs(cc_soc_sw - chip->cl.init_cc_soc_sw)) + * 10000, CC_SOC_30BIT); + delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_100pct, + 10000); +#endif chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%d total_cc_uah=%lld\n", cc_soc_sw, cc_soc_delta_pct, chip->cl.final_cc_uah); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + fg_dbg(chip, FG_SOMC, + "cc_soc_sw=%d cc_soc_delta_100pct=%lld total_cc_uah=%lld\n", + cc_soc_sw, cc_soc_delta_100pct, chip->cl.final_cc_uah); +#endif return 0; } @@ -1434,8 +1748,19 @@ static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc) chip->cl.init_cc_soc_sw = cc_soc_sw; chip->cl.active = true; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) fg_dbg(chip, FG_CAP_LEARN, "Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n", batt_soc_msb, chip->cl.init_cc_soc_sw); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chip->cl.max_ccsoc_during_active = cc_soc_sw; + chip->cl.max_bsoc_during_active = batt_soc; + chip->cl.max_bsoc_time_ms = ktime_to_ms(ktime_get_boottime()); + chip->cl.start_time_ms = chip->cl.max_bsoc_time_ms; + fg_dbg(chip, FG_SOMC, + "Capacity learning started. bsoc:%d cc_soc_sw:%d time:%lld\n", + batt_soc, cc_soc_sw, chip->cl.start_time_ms); +#endif out: return rc; } @@ -1466,10 +1791,32 @@ out: return rc; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define SOC_MAX_RANGE 999985458LL /* 0.999985458 * (10^9) */ +#define SOC_LSB 15300LL /* 1.53E-05 * (10^9) */ +#define BATT_SOC_MAX_RANGE 1000001530000LL /* 1.00000153 * (10^12) */ +#define BATT_SOC_LSB 233LL /* 2.33E-10 * (10^12) */ +#define CC_SOC_MAX_RANGE 1000000455000LL /* (2.00000091/2) * (10^12) */ +#define CC_SOC_LSB 931LL /* 9.31E-10 * (10^12) */ + +#define CL_ABORT_BSOC_10PER 20 /* 2.0 persetnt */ +#define CL_ABORT_BSOC_RAW (int)((CL_ABORT_BSOC_10PER * \ + BATT_SOC_MAX_RANGE) / (BATT_SOC_LSB * 1000)) +#define CL_ABORT_CCSOC_10PER 5 /* 0.5 percent */ +#define CL_ABORT_CCSOC_RAW (int)((CL_ABORT_CCSOC_10PER * CC_SOC_MAX_RANGE)\ + / (CC_SOC_LSB * 1000)) +#define CL_ABORT_KEEP_TIMEOUT_MS (7 * 60 * 60 * 1000) +#define CL_ABORT_SLOW_TIMEOUT_MS (10 * 60 * 60 * 1000) +#endif static void fg_cap_learning_update(struct fg_chip *chip) { int rc, batt_soc, batt_soc_msb; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) bool input_present = is_input_present(chip); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int msoc, cc_soc_sw; +#endif mutex_lock(&chip->cl.lock); @@ -1492,6 +1839,14 @@ static void fg_cap_learning_update(struct fg_chip *chip) fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n", chip->charge_status, chip->cl.active, batt_soc_msb); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw); + if (rc < 0) { + pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc); + goto out; + } + +#endif /* Initialize the starting point of learning capacity */ if (!chip->cl.active) { if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) { @@ -1501,15 +1856,34 @@ static void fg_cap_learning_update(struct fg_chip *chip) } else { if (chip->charge_done) { +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + rc = fg_get_prop_capacity(chip, &msoc); + if (rc < 0) { + pr_err("Error in getting capacity rc=%d\n", rc); + goto deactive; + } + if (msoc < 100) { + fg_dbg(chip, FG_SOMC, + "learning aborted due to not 100pc %d\n", + msoc); + goto deactive; + } +#endif rc = fg_cap_learning_done(chip); if (rc < 0) pr_err("Error in completing capacity learning, rc=%d\n", rc); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) chip->cl.active = false; chip->cl.init_cc_uah = 0; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + goto deactive; +#endif } +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) { if (!input_present) { fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n", @@ -1534,6 +1908,55 @@ static void fg_cap_learning_update(struct fg_chip *chip) chip->cl.init_cc_uah = 0; } } +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chip->cl.batt_soc_drop = + chip->cl.max_bsoc_during_active - batt_soc; + chip->cl.cc_soc_drop = + chip->cl.max_ccsoc_during_active - cc_soc_sw; + chip->cl.hold_time = ktime_to_ms(ktime_get_boottime()) - + chip->cl.max_bsoc_time_ms; + chip->cl.total_time = ktime_to_ms(ktime_get_boottime()) - + chip->cl.start_time_ms; + + if (chip->cl.cc_soc_drop > CL_ABORT_CCSOC_RAW) { + fg_dbg(chip, FG_SOMC, + "CL aborted due to cc_soc_sw drop from %d to %d", + chip->cl.max_ccsoc_during_active, cc_soc_sw); + goto deactive; + } else if (chip->cl.batt_soc_drop > CL_ABORT_BSOC_RAW) { + fg_dbg(chip, FG_SOMC, + "CL aborted due to bsoc drop from %d to %d", + chip->cl.max_bsoc_during_active, batt_soc); + goto deactive; + } else if (chip->cl.hold_time > CL_ABORT_KEEP_TIMEOUT_MS) { + fg_dbg(chip, FG_SOMC, + "CL aborted due to soc holding for long hours"); + goto deactive; + } else if (chip->cl.total_time > CL_ABORT_SLOW_TIMEOUT_MS) { + fg_dbg(chip, FG_SOMC, + "CL aborted due to slow charging"); + goto deactive; + } + + /* reset params if increasing */ + if (chip->cl.batt_soc_drop < 0 || chip->cl.cc_soc_drop < 0) { + chip->cl.max_ccsoc_during_active = cc_soc_sw; + chip->cl.max_bsoc_during_active = batt_soc; + chip->cl.max_bsoc_time_ms = + ktime_to_ms(ktime_get_boottime()); + chip->cl.cc_soc_drop = 0; + chip->cl.batt_soc_drop = 0; + fg_dbg(chip, FG_CAP_LEARN, + "max bsoc/ccsoc updated: %d/%d\n", + chip->cl.max_bsoc_during_active, + chip->cl.max_ccsoc_during_active); + } + goto out; +deactive: + chip->cl.active = false; + chip->cl.init_cc_uah = 0; +#endif } out: @@ -1637,9 +2060,11 @@ static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv) if (chip->wa_flags & PMI8998_V1_REV_WA) return 0; - if (voltage_mv == chip->last_recharge_volt_mv) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chip->recharge_voltage_mv == voltage_mv) return 0; +#endif fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n", voltage_mv); fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf); @@ -1654,7 +2079,9 @@ static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv) return rc; } - chip->last_recharge_volt_mv = voltage_mv; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chip->recharge_voltage_mv = voltage_mv; +#endif return 0; } @@ -1662,8 +2089,12 @@ static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv) static int fg_charge_full_update(struct fg_chip *chip) { union power_supply_propval prop = {0, }; - int rc, msoc, bsoc, recharge_soc, msoc_raw; + int rc, msoc, bsoc, recharge_soc; u8 full_soc[2] = {0xFF, 0xFF}; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + bool need_monotonic_soc_update = false; + int cc_soc_sw; +#endif if (!chip->dt.hold_soc_while_full) return 0; @@ -1698,11 +2129,11 @@ static int fg_charge_full_update(struct fg_chip *chip) pr_err("Error in getting msoc, rc=%d\n", rc); goto out; } - msoc_raw = DIV_ROUND_CLOSEST(msoc * FULL_SOC_RAW, FULL_CAPACITY); fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n", msoc, bsoc, chip->health, chip->charge_status, chip->charge_full); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (chip->charge_done && !chip->charge_full) { if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD) { fg_dbg(chip, FG_STATUS, "Setting charge_full to true\n"); @@ -1722,7 +2153,7 @@ static int fg_charge_full_update(struct fg_chip *chip) fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n", msoc); } - } else if (msoc_raw < recharge_soc && chip->charge_full) { + } else if ((bsoc >> 8) <= recharge_soc && chip->charge_full) { chip->delta_soc = FULL_CAPACITY - msoc; /* @@ -1752,8 +2183,8 @@ static int fg_charge_full_update(struct fg_chip *chip) rc); goto out; } - fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n", - msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc); + fg_dbg(chip, FG_STATUS, "bsoc: %d recharge_soc: %d delta_soc: %d\n", + bsoc >> 8, recharge_soc, chip->delta_soc); } else { goto out; } @@ -1781,6 +2212,106 @@ static int fg_charge_full_update(struct fg_chip *chip) } fg_dbg(chip, FG_STATUS, "Set charge_full to true @ soc %d\n", msoc); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chip->charge_full) { + if (chip->charge_done) { + if ((bsoc >> 8) <= recharge_soc && + !chip->recharge_starting) { + fg_dbg(chip, FG_SOMC, "Cause to recharge\n"); + rc = fg_set_recharge_voltage(chip, + chip->bp.float_volt_uv / 1000); + if (rc < 0) { + pr_err("Error in recharge rc=%d\n", rc); + goto out; + } + chip->recharge_starting = true; + need_monotonic_soc_update = true; + } else { + fg_dbg(chip, FG_SOMC, + "Other case during charge_full.\n"); + } + } else if (chip->charge_status == + POWER_SUPPLY_STATUS_CHARGING) { + fg_dbg(chip, FG_SOMC, "Confirmed recharging\n"); + rc = fg_set_recharge_voltage(chip, + AUTO_RECHG_VOLT_LOW_LIMIT_MV); + if (rc < 0) { + pr_err("Error in recharge voltage rc=%d\n", rc); + goto out; + } + chip->recharge_starting = false; + chip->charge_full = false; + } else if (chip->charge_status == + POWER_SUPPLY_STATUS_DISCHARGING || + chip->charge_status == + POWER_SUPPLY_STATUS_NOT_CHARGING) { + fg_dbg(chip, FG_SOMC, "Removed during full\n"); + fg_dbg(chip, FG_SOMC, "Undo recharge voltage thresh\n"); + rc = fg_set_recharge_voltage(chip, + AUTO_RECHG_VOLT_LOW_LIMIT_MV); + if (rc < 0) { + pr_err("Error in recharge voltage rc=%d\n", rc); + goto out; + } + chip->charge_full = false; + need_monotonic_soc_update = true; + } else { + fg_dbg(chip, FG_SOMC, "Invalid charge_status %d\n", + chip->charge_status); + } + } else { + if (chip->charge_done) { + fg_dbg(chip, FG_SOMC, "Undo recharge voltage thresh\n"); + rc = fg_set_recharge_voltage(chip, + AUTO_RECHG_VOLT_LOW_LIMIT_MV); + if (rc < 0) { + pr_err("Error in recharge voltage rc=%d\n", rc); + goto out; + } + if (msoc >= 99 && + chip->health == POWER_SUPPLY_HEALTH_GOOD) { + fg_dbg(chip, FG_SOMC, "Detected FULL\n"); + chip->charge_full = true; + need_monotonic_soc_update = true; + } + /* Write a FULL value to cc_soc_sw */ + cc_soc_sw = CC_SOC_30BIT; + rc = fg_sram_write(chip, + chip->sp[FG_SRAM_CC_SOC_SW].addr_word, + chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, + (u8 *)&cc_soc_sw, + chip->sp[FG_SRAM_CC_SOC_SW].len, + FG_IMA_ATOMIC); + if (rc < 0) { + pr_err("Error in writing cc_soc_sw, rc=%d\n", + rc); + goto out; + } + } else { + fg_dbg(chip, FG_STATUS, + "Other case during not charge_full.\n"); + } + } + if (need_monotonic_soc_update) { + fg_dbg(chip, FG_SOMC, "Update FULL_SOC to bsoc=%d\n", bsoc); + rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, + (u8 *)&bsoc, 2, FG_IMA_ATOMIC); + if (rc < 0) { + pr_err("failed to write full_soc rc=%d\n", rc); + goto out; + } + + fg_dbg(chip, FG_SOMC, "Update MONOTONIC SOC to 100\n"); + rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, + MONOTONIC_SOC_OFFSET, + full_soc, 2, FG_IMA_ATOMIC); + if (rc < 0) { + pr_err("failed to write monotonic_soc rc=%d\n", rc); + goto out; + } + } +#endif out: mutex_unlock(&chip->charge_full_lock); return rc; @@ -1965,33 +2496,6 @@ static int fg_adjust_recharge_soc(struct fg_chip *chip) return 0; } -static int fg_adjust_recharge_voltage(struct fg_chip *chip) -{ - int rc, recharge_volt_mv; - - if (chip->dt.auto_recharge_soc) - return 0; - - fg_dbg(chip, FG_STATUS, "health: %d chg_status: %d chg_done: %d\n", - chip->health, chip->charge_status, chip->charge_done); - - recharge_volt_mv = chip->dt.recharge_volt_thr_mv; - - /* Lower the recharge voltage in soft JEITA */ - if (chip->health == POWER_SUPPLY_HEALTH_WARM || - chip->health == POWER_SUPPLY_HEALTH_COOL) - recharge_volt_mv -= 200; - - rc = fg_set_recharge_voltage(chip, recharge_volt_mv); - if (rc < 0) { - pr_err("Error in setting recharge_voltage, rc=%d\n", - rc); - return rc; - } - - return 0; -} - static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp) { enum slope_limit_status status; @@ -2209,86 +2713,118 @@ static int fg_esr_timer_config(struct fg_chip *chip, bool sleep) return 0; } -static void fg_ttf_update(struct fg_chip *chip) +static void fg_batt_avg_update(struct fg_chip *chip) { - int rc; - int delay_ms; - union power_supply_propval prop = {0, }; - int online = 0; + if (chip->charge_status == chip->prev_charge_status) + return; - if (usb_psy_initialized(chip)) { - rc = power_supply_get_property(chip->usb_psy, - POWER_SUPPLY_PROP_ONLINE, &prop); - if (rc < 0) { - pr_err("Couldn't read usb ONLINE prop rc=%d\n", rc); - return; - } + cancel_delayed_work_sync(&chip->batt_avg_work); + fg_circ_buf_clr(&chip->ibatt_circ_buf); + fg_circ_buf_clr(&chip->vbatt_circ_buf); - online = online || prop.intval; - } + if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING || + chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) + schedule_delayed_work(&chip->batt_avg_work, + msecs_to_jiffies(2000)); +} - if (pc_port_psy_initialized(chip)) { - rc = power_supply_get_property(chip->pc_port_psy, - POWER_SUPPLY_PROP_ONLINE, &prop); - if (rc < 0) { - pr_err("Couldn't read pc_port ONLINE prop rc=%d\n", rc); - return; - } +static void status_change_work(struct work_struct *work) +{ + struct fg_chip *chip = container_of(work, + struct fg_chip, status_change_work); + union power_supply_propval prop = {0, }; + int rc, batt_temp; - online = online || prop.intval; + if (!batt_psy_initialized(chip)) { + fg_dbg(chip, FG_STATUS, "Charger not available?!\n"); + goto out; } - if (dc_psy_initialized(chip)) { - rc = power_supply_get_property(chip->dc_psy, - POWER_SUPPLY_PROP_ONLINE, &prop); - if (rc < 0) { - pr_err("Couldn't read dc ONLINE prop rc=%d\n", rc); - return; - } + rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, + &prop); + if (rc < 0) { + pr_err("Error in getting charging status, rc=%d\n", rc); + goto out; + } - online = online || prop.intval; + chip->prev_charge_status = chip->charge_status; + chip->charge_status = prop.intval; + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &prop); + if (rc < 0) { + pr_err("Error in getting charge type, rc=%d\n", rc); + goto out; } + chip->charge_type = prop.intval; + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_DONE, &prop); + if (rc < 0) { + pr_err("Error in getting charge_done, rc=%d\n", rc); + goto out; + } - if (chip->online_status == online) - return; + chip->charge_done = prop.intval; + if (chip->cyc_ctr.en) + schedule_work(&chip->cycle_count_work); - chip->online_status = online; - if (online) - /* wait 35 seconds for the input to settle */ - delay_ms = 35000; - else - /* wait 5 seconds for current to settle during discharge */ - delay_ms = 5000; - - vote(chip->awake_votable, TTF_PRIMING, true, 0); - cancel_delayed_work_sync(&chip->ttf_work); - mutex_lock(&chip->ttf.lock); - fg_circ_buf_clr(&chip->ttf.ibatt); - fg_circ_buf_clr(&chip->ttf.vbatt); - chip->ttf.last_ttf = 0; - chip->ttf.last_ms = 0; - mutex_unlock(&chip->ttf.lock); - schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms)); -} + fg_cap_learning_update(chip); -static void restore_cycle_counter(struct fg_chip *chip) -{ - int rc = 0, i; - u8 data[2]; + rc = fg_charge_full_update(chip); + if (rc < 0) + pr_err("Error in charge_full_update, rc=%d\n", rc); - if (!chip->cyc_ctr.en) - return; + rc = fg_adjust_recharge_soc(chip); + if (rc < 0) + pr_err("Error in adjusting recharge_soc, rc=%d\n", rc); - mutex_lock(&chip->cyc_ctr.lock); - for (i = 0; i < BUCKET_COUNT; i++) { - rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2), - CYCLE_COUNT_OFFSET + (i % 2) * 2, data, 2, - FG_IMA_DEFAULT); - if (rc < 0) - pr_err("failed to read bucket %d rc=%d\n", i, rc); - else - chip->cyc_ctr.count[i] = data[0] | data[1] << 8; + rc = fg_adjust_ki_coeff_dischg(chip); + if (rc < 0) + pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc); + + rc = fg_esr_fcc_config(chip); + if (rc < 0) + pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); + + rc = fg_esr_timer_config(chip, false); + if (rc < 0) + pr_err("Error in configuring ESR timer, rc=%d\n", rc); + + rc = fg_get_battery_temp(chip, &batt_temp); + if (!rc) { + rc = fg_slope_limit_config(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring slope limiter rc:%d\n", + rc); + + rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", + rc); + } + + fg_batt_avg_update(chip); + +out: + fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n", + chip->charge_status, chip->charge_type, chip->charge_done); + pm_relax(chip->dev); +} + +static void restore_cycle_counter(struct fg_chip *chip) +{ + int rc = 0, i; + u8 data[2]; + + mutex_lock(&chip->cyc_ctr.lock); + for (i = 0; i < BUCKET_COUNT; i++) { + rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2), + CYCLE_COUNT_OFFSET + (i % 2) * 2, data, 2, + FG_IMA_DEFAULT); + if (rc < 0) + pr_err("failed to read bucket %d rc=%d\n", i, rc); + else + chip->cyc_ctr.count[i] = data[0] | data[1] << 8; } mutex_unlock(&chip->cyc_ctr.lock); } @@ -2333,25 +2869,20 @@ static int fg_inc_store_cycle_ctr(struct fg_chip *chip, int bucket) rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2), CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2, FG_IMA_DEFAULT); - if (rc < 0) { + if (rc < 0) pr_err("failed to write BATT_CYCLE[%d] rc=%d\n", bucket, rc); - return rc; - } - - chip->cyc_ctr.count[bucket] = cyc_count; - fg_dbg(chip, FG_STATUS, "Stored count %d in bucket %d\n", cyc_count, - bucket); - + else + chip->cyc_ctr.count[bucket] = cyc_count; return rc; } -static void fg_cycle_counter_update(struct fg_chip *chip) +static void cycle_count_work(struct work_struct *work) { int rc = 0, bucket, i, batt_soc; - - if (!chip->cyc_ctr.en) - return; + struct fg_chip *chip = container_of(work, + struct fg_chip, + cycle_count_work); mutex_lock(&chip->cyc_ctr.lock); rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc); @@ -2363,30 +2894,45 @@ static void fg_cycle_counter_update(struct fg_chip *chip) /* We need only the most significant byte here */ batt_soc = (u32)batt_soc >> 24; - /* Find out which bucket the SOC falls in */ - bucket = batt_soc / BUCKET_SOC_PCT; - if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) { + /* Find out which bucket the SOC falls in */ + bucket = batt_soc / BUCKET_SOC_PCT; + pr_debug("batt_soc: %d bucket: %d\n", batt_soc, bucket); + + /* + * If we've started counting for the previous bucket, + * then store the counter for that bucket if the + * counter for current bucket is getting started. + */ + if (bucket > 0 && chip->cyc_ctr.started[bucket - 1] && + !chip->cyc_ctr.started[bucket]) { + rc = fg_inc_store_cycle_ctr(chip, bucket - 1); + if (rc < 0) { + pr_err("Error in storing cycle_ctr rc: %d\n", + rc); + goto out; + } else { + chip->cyc_ctr.started[bucket - 1] = false; + chip->cyc_ctr.last_soc[bucket - 1] = 0; + } + } if (!chip->cyc_ctr.started[bucket]) { chip->cyc_ctr.started[bucket] = true; chip->cyc_ctr.last_soc[bucket] = batt_soc; } - } else if (chip->charge_done || !is_input_present(chip)) { + } else { for (i = 0; i < BUCKET_COUNT; i++) { if (chip->cyc_ctr.started[i] && - batt_soc > chip->cyc_ctr.last_soc[i] + 2) { + batt_soc > chip->cyc_ctr.last_soc[i]) { rc = fg_inc_store_cycle_ctr(chip, i); if (rc < 0) pr_err("Error in storing cycle_ctr rc: %d\n", rc); chip->cyc_ctr.last_soc[i] = 0; - chip->cyc_ctr.started[i] = false; } + chip->cyc_ctr.started[i] = false; } } - - fg_dbg(chip, FG_STATUS, "batt_soc: %d bucket: %d chg_status: %d\n", - batt_soc, bucket, chip->charge_status); out: mutex_unlock(&chip->cyc_ctr.lock); } @@ -2407,87 +2953,6 @@ static int fg_get_cycle_count(struct fg_chip *chip) return count; } -static void status_change_work(struct work_struct *work) -{ - struct fg_chip *chip = container_of(work, - struct fg_chip, status_change_work); - union power_supply_propval prop = {0, }; - int rc, batt_temp; - - if (!batt_psy_initialized(chip)) { - fg_dbg(chip, FG_STATUS, "Charger not available?!\n"); - goto out; - } - - rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, - &prop); - if (rc < 0) { - pr_err("Error in getting charging status, rc=%d\n", rc); - goto out; - } - - chip->prev_charge_status = chip->charge_status; - chip->charge_status = prop.intval; - rc = power_supply_get_property(chip->batt_psy, - POWER_SUPPLY_PROP_CHARGE_TYPE, &prop); - if (rc < 0) { - pr_err("Error in getting charge type, rc=%d\n", rc); - goto out; - } - - chip->charge_type = prop.intval; - rc = power_supply_get_property(chip->batt_psy, - POWER_SUPPLY_PROP_CHARGE_DONE, &prop); - if (rc < 0) { - pr_err("Error in getting charge_done, rc=%d\n", rc); - goto out; - } - - chip->charge_done = prop.intval; - fg_cycle_counter_update(chip); - fg_cap_learning_update(chip); - - rc = fg_charge_full_update(chip); - if (rc < 0) - pr_err("Error in charge_full_update, rc=%d\n", rc); - - rc = fg_adjust_recharge_soc(chip); - if (rc < 0) - pr_err("Error in adjusting recharge_soc, rc=%d\n", rc); - - rc = fg_adjust_recharge_voltage(chip); - if (rc < 0) - pr_err("Error in adjusting recharge_voltage, rc=%d\n", rc); - - rc = fg_adjust_ki_coeff_dischg(chip); - if (rc < 0) - pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc); - - rc = fg_esr_fcc_config(chip); - if (rc < 0) - pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); - - rc = fg_get_battery_temp(chip, &batt_temp); - if (!rc) { - rc = fg_slope_limit_config(chip, batt_temp); - if (rc < 0) - pr_err("Error in configuring slope limiter rc:%d\n", - rc); - - rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp); - if (rc < 0) - pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", - rc); - } - - fg_ttf_update(chip); - -out: - fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n", - chip->charge_status, chip->charge_type, chip->charge_done); - pm_relax(chip->dev); -} - static int fg_bp_params_config(struct fg_chip *chip) { int rc = 0; @@ -2556,6 +3021,7 @@ static bool is_profile_load_required(struct fg_chip *chip) } profiles_same = memcmp(chip->batt_profile, buf, PROFILE_COMP_LEN) == 0; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (profiles_same) { fg_dbg(chip, FG_STATUS, "Battery profile is same, not loading it\n"); return false; @@ -2575,8 +3041,39 @@ static bool is_profile_load_required(struct fg_chip *chip) } fg_dbg(chip, FG_STATUS, "Profiles are different, loading the correct one\n"); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (profiles_same && !chip->dt.force_load_profile) { + fg_dbg(chip, FG_SOMC, "Battery profile is same, not loading it since force_load_profile is disabled\n"); + return false; + } + + if (!profiles_same) { + fg_dbg(chip, FG_SOMC, "Profiles are different, loading the correct one\n"); + if (fg_sram_dump) { + fg_dbg(chip, FG_SOMC, "FG: loaded profile:\n"); + dump_sram(buf, PROFILE_LOAD_WORD, + PROFILE_COMP_LEN); + fg_dbg(chip, FG_SOMC, "FG: available profile:\n"); + dump_sram(chip->batt_profile, PROFILE_LOAD_WORD, + PROFILE_LEN); + } + } else { + fg_dbg(chip, FG_SOMC, "force_load_profile is enabled, loading the correct one\n"); + if (fg_sram_dump) { + fg_dbg(chip, FG_SOMC, "FG: loaded profile:\n"); + dump_sram(chip->batt_profile, PROFILE_LOAD_WORD, + PROFILE_LEN); + } + } +#endif } else { +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) fg_dbg(chip, FG_STATUS, "Profile integrity bit is not set\n"); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + fg_dbg(chip, FG_SOMC, "Profile integrity bit is not set\n"); +#endif if (fg_profile_dump) { pr_info("FG: profile to be loaded:\n"); dump_sram(chip->batt_profile, PROFILE_LOAD_WORD, @@ -2643,6 +3140,72 @@ out: return rc; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +static int fg_somc_write_back_sram_params(struct fg_chip *chip) +{ + int rc; + int16_t act_cap_mah; + u8 buf[4], val; + + /* Rewrite the CYCLE_COUNT */ + rc = fg_sram_write(chip, CYCLE_COUNT_WORD, CYCLE_COUNT_OFFSET, + (u8 *)&chip->cyc_ctr.count, + sizeof(chip->cyc_ctr.count) / sizeof(u8 *), + FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in rewriting cycle counter, rc=%d\n", rc); + return rc; + } + + /* Rewrite the ACT_BATT_CAP_BKUP */ + act_cap_mah = div64_s64(chip->cl.learned_cc_uah, 1000); + rc = fg_sram_write(chip, chip->sp[FG_SRAM_ACT_BATT_CAP].addr_word, + chip->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, + (u8 *)&act_cap_mah, chip->sp[FG_SRAM_ACT_BATT_CAP].len, + FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in rewriting act_batt_cap_bkup, rc=%d\n", rc); + return rc; + } + + /* Write the BATT_AGING_LEVEL */ + val = chip->batt_aging_level; + rc = fg_sram_write(chip, BATT_AGING_LEVEL_WORD, + BATT_AGING_LEVEL_OFFSET, &val, 1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing batt_aging_level, rc=%d\n", rc); + return rc; + } + + /* This SRAM register is only present in v2.0 and above */ + if (!(chip->wa_flags & PMI8998_V1_REV_WA) && + chip->bp.float_volt_uv > 0) { + fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT, + chip->bp.float_volt_uv / 1000, buf); + rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word, + chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, buf, + chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing float_volt, rc=%d\n", rc); + return rc; + } + } + + if (chip->bp.vbatt_full_mv > 0) { + rc = fg_set_constant_chg_voltage(chip, + chip->bp.vbatt_full_mv * 1000); + if (rc < 0) + return rc; + } + + return 0; +} + +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define VBATT_RANGE_CHARGE_UV 250000 +#define VBATT_RANGE_DISCHARGE_UV 250000 +#endif static void profile_load_work(struct work_struct *work) { struct fg_chip *chip = container_of(work, @@ -2650,6 +3213,9 @@ static void profile_load_work(struct work_struct *work) profile_load_work.work); u8 buf[2], val; int rc; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int vbatt_predict_uv, vbatt_uv; +#endif vote(chip->awake_votable, PROFILE_LOAD, true, 0); @@ -2668,15 +3234,57 @@ static void profile_load_work(struct work_struct *work) if (!chip->profile_available) goto out; - +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (!is_profile_load_required(chip)) goto done; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (!is_profile_load_required(chip)) { + rc = fg_get_vbatt_predict(chip, &vbatt_predict_uv); + if (rc < 0) { + pr_err("failed to get battery voltage, rc=%d\n", rc); + goto out; + } + rc = fg_get_battery_voltage(chip, &vbatt_uv); + if (rc < 0) { + pr_err("failed to get battery voltage, rc=%d\n", rc); + goto out; + } + fg_dbg(chip, FG_SOMC, "VBATT vs PREDICT : %d vs %d\n", + vbatt_uv, vbatt_predict_uv); + + if (vbatt_predict_uv - vbatt_uv > VBATT_RANGE_DISCHARGE_UV || + vbatt_uv - vbatt_predict_uv > VBATT_RANGE_CHARGE_UV) { + fg_dbg(chip, FG_SOMC, + "out of range. So restart FG\n"); + rc = __fg_restart(chip); + if (rc < 0) { + pr_err("Error in restarting FG, rc=%d\n", rc); + goto out; + } + fg_dbg(chip, FG_SOMC, "SOC is ready\n"); + } + goto done; + } +#endif + +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) clear_cycle_counter(chip); mutex_lock(&chip->cl.lock); chip->cl.learned_cc_uah = 0; chip->cl.active = false; mutex_unlock(&chip->cl.lock); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chip->batt_aging_level == chip->saved_batt_aging_level) { + clear_cycle_counter(chip); + mutex_lock(&chip->cl.lock); + chip->cl.learned_cc_uah = 0; + chip->cl.active = false; + mutex_unlock(&chip->cl.lock); + } +#endif fg_dbg(chip, FG_STATUS, "profile loading started\n"); rc = fg_masked_write(chip, BATT_SOC_RESTART(chip), RESTART_GO_BIT, 0); @@ -2694,6 +3302,16 @@ static void profile_load_work(struct work_struct *work) goto out; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chip->batt_aging_level != chip->saved_batt_aging_level) { + rc = fg_somc_write_back_sram_params(chip); + if (rc < 0) { + pr_err("Error in write sram params, rc=%d\n", rc); + goto out; + } + } + +#endif rc = __fg_restart(chip); if (rc < 0) { pr_err("Error in restarting FG, rc=%d\n", rc); @@ -2711,6 +3329,9 @@ static void profile_load_work(struct work_struct *work) goto out; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chip->saved_batt_aging_level = chip->batt_aging_level; +#endif done: rc = fg_bp_params_config(chip); if (rc < 0) @@ -2735,6 +3356,9 @@ done: chip->profile_loaded = true; fg_dbg(chip, FG_STATUS, "profile loaded successfully"); out: +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chip->batt_aging_level = chip->saved_batt_aging_level; +#endif chip->soc_reporting_ready = true; vote(chip->awake_votable, PROFILE_LOAD, false, 0); } @@ -2848,19 +3472,45 @@ static struct kernel_param_ops fg_restart_ops = { module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644); +#define BATT_AVG_POLL_PERIOD_MS 10000 +static void batt_avg_work(struct work_struct *work) +{ + struct fg_chip *chip = container_of(work, struct fg_chip, + batt_avg_work.work); + int rc, ibatt_now, vbatt_now; + + mutex_lock(&chip->batt_avg_lock); + rc = fg_get_battery_current(chip, &ibatt_now); + if (rc < 0) { + pr_err("failed to get battery current, rc=%d\n", rc); + goto reschedule; + } + + rc = fg_get_battery_voltage(chip, &vbatt_now); + if (rc < 0) { + pr_err("failed to get battery voltage, rc=%d\n", rc); + goto reschedule; + } + + fg_circ_buf_add(&chip->ibatt_circ_buf, ibatt_now); + fg_circ_buf_add(&chip->vbatt_circ_buf, vbatt_now); + +reschedule: + mutex_unlock(&chip->batt_avg_lock); + schedule_delayed_work(&chip->batt_avg_work, + msecs_to_jiffies(BATT_AVG_POLL_PERIOD_MS)); +} + #define HOURS_TO_SECONDS 3600 #define OCV_SLOPE_UV 10869 #define MILLI_UNIT 1000 #define MICRO_UNIT 1000000 -#define NANO_UNIT 1000000000 -static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) +static int fg_get_time_to_full(struct fg_chip *chip, int *val) { - int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah, - i_cc2cv, soc_cc2cv, tau, divisor, iterm, ttf_mode, - i, soc_per_step, msoc_this_step, msoc_next_step, - ibatt_this_step, t_predicted_this_step, ttf_slope, - t_predicted_cv, t_predicted = 0; - s64 delta_ms; + int rc, ibatt_avg, vbatt_avg, rbatt, msoc, ocv_cc2cv, full_soc, + act_cap_uah; + s32 i_cc2cv, soc_cc2cv, ln_val, centi_tau_scale; + s64 t_predicted_cc = 0, t_predicted_cv = 0; if (chip->bp.float_volt_uv <= 0) { pr_err("battery profile is not loaded\n"); @@ -2879,53 +3529,48 @@ static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) } fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc); - /* the battery is considered full if the SOC is 100% */ if (msoc >= 100) { *val = 0; return 0; } - if (is_qnovo_en(chip)) - ttf_mode = TTF_MODE_QNOVO; - else - ttf_mode = TTF_MODE_NORMAL; - - /* when switching TTF algorithms the TTF needs to be reset */ - if (chip->ttf.mode != ttf_mode) { - fg_circ_buf_clr(&chip->ttf.ibatt); - fg_circ_buf_clr(&chip->ttf.vbatt); - chip->ttf.last_ttf = 0; - chip->ttf.last_ms = 0; - chip->ttf.mode = ttf_mode; - } - - /* at least 10 samples are required to produce a stable IBATT */ - if (chip->ttf.ibatt.size < 10) { - *val = -1; - return 0; - } - - rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg); + mutex_lock(&chip->batt_avg_lock); + rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg); if (rc < 0) { - pr_err("failed to get IBATT AVG rc=%d\n", rc); - return rc; + /* try to get instantaneous current */ + rc = fg_get_battery_current(chip, &ibatt_avg); + if (rc < 0) { + mutex_unlock(&chip->batt_avg_lock); + pr_err("failed to get battery current, rc=%d\n", rc); + return rc; + } } - rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_avg); + rc = fg_circ_buf_avg(&chip->vbatt_circ_buf, &vbatt_avg); if (rc < 0) { - pr_err("failed to get VBATT AVG rc=%d\n", rc); - return rc; + /* try to get instantaneous voltage */ + rc = fg_get_battery_voltage(chip, &vbatt_avg); + if (rc < 0) { + mutex_unlock(&chip->batt_avg_lock); + pr_err("failed to get battery voltage, rc=%d\n", rc); + return rc; + } } - ibatt_avg = -ibatt_avg / MILLI_UNIT; - vbatt_avg /= MILLI_UNIT; - - /* clamp ibatt_avg to iterm */ - if (ibatt_avg < abs(chip->dt.sys_term_curr_ma)) - ibatt_avg = abs(chip->dt.sys_term_curr_ma); + mutex_unlock(&chip->batt_avg_lock); + fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg); + /* clamp ibatt_avg to -150mA */ + if (ibatt_avg > -150000) + ibatt_avg = -150000; fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg); - fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg); + + /* reverse polarity to be consistent with unsigned current settings */ + ibatt_avg = abs(ibatt_avg); + + /* estimated battery current at the CC to CV transition */ + i_cc2cv = div_s64((s64)ibatt_avg * vbatt_avg, chip->bp.float_volt_uv); + fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv); rc = fg_get_battery_resistance(chip, &rbatt); if (rc < 0) { @@ -2933,14 +3578,19 @@ static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) return rc; } - rbatt /= MILLI_UNIT; + /* clamp rbatt to 50mOhms */ + if (rbatt < 50000) + rbatt = 50000; + fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt); - rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); + rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah); if (rc < 0) { pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc); return rc; } + act_cap_uah *= MILLI_UNIT; + fg_dbg(chip, FG_TTF, "actual_capacity_uah=%d\n", act_cap_uah); rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc); if (rc < 0) { @@ -2949,148 +3599,69 @@ static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) } full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY, FULL_SOC_RAW); - act_cap_mah = full_soc * act_cap_mah / 100; - fg_dbg(chip, FG_TTF, "act_cap_mah=%d\n", act_cap_mah); - - /* estimated battery current at the CC to CV transition */ - switch (chip->ttf.mode) { - case TTF_MODE_NORMAL: - i_cc2cv = ibatt_avg * vbatt_avg / - max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT); - break; - case TTF_MODE_QNOVO: - i_cc2cv = min( - chip->ttf.cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT, - ibatt_avg * vbatt_avg / - max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT)); - break; - default: - pr_err("TTF mode %d is not supported\n", chip->ttf.mode); - break; - } - fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv); + fg_dbg(chip, FG_TTF, "full_soc=%d\n", full_soc); /* if we are already in CV state then we can skip estimating CC */ if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER) - goto cv_estimate; + goto skip_cc_estimate; + + /* if the charger is current limited then use power approximation */ + if (ibatt_avg > chip->bp.fastchg_curr_ma * MILLI_UNIT - 50000) + ocv_cc2cv = div_s64((s64)rbatt * ibatt_avg, MICRO_UNIT); + else + ocv_cc2cv = div_s64((s64)rbatt * i_cc2cv, MICRO_UNIT); + ocv_cc2cv = chip->bp.float_volt_uv - ocv_cc2cv; + fg_dbg(chip, FG_TTF, "ocv_cc2cv=%d\n", ocv_cc2cv); + soc_cc2cv = div_s64(chip->bp.float_volt_uv - ocv_cc2cv, OCV_SLOPE_UV); /* estimated SOC at the CC to CV transition */ - soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV); soc_cc2cv = 100 - soc_cc2cv; fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv); - switch (chip->ttf.mode) { - case TTF_MODE_NORMAL: - if (soc_cc2cv - msoc <= 0) - goto cv_estimate; + /* the esimated SOC may be lower than the current SOC */ + if (soc_cc2cv - msoc <= 0) + goto skip_cc_estimate; - divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100); - t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) * - HOURS_TO_SECONDS, divisor); - break; - case TTF_MODE_QNOVO: - soc_per_step = 100 / MAX_CC_STEPS; - for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) { - msoc_next_step = (i + 1) * soc_per_step; - if (i == msoc / soc_per_step) - msoc_this_step = msoc; - else - msoc_this_step = i * soc_per_step; - - /* scale ibatt by 85% to account for discharge pulses */ - ibatt_this_step = min( - chip->ttf.cc_step.arr[i] / MILLI_UNIT, - ibatt_avg) * 85 / 100; - divisor = max(100, ibatt_this_step * 100); - t_predicted_this_step = div_s64((s64)act_cap_mah * - (msoc_next_step - msoc_this_step) * - HOURS_TO_SECONDS, divisor); - t_predicted += t_predicted_this_step; - fg_dbg(chip, FG_TTF, "[%d, %d] ma=%d t=%d\n", - msoc_this_step, msoc_next_step, - ibatt_this_step, t_predicted_this_step); - } - break; - default: - pr_err("TTF mode %d is not supported\n", chip->ttf.mode); - break; - } + t_predicted_cc = div_s64((s64)full_soc * act_cap_uah, 100); + t_predicted_cc = div_s64(t_predicted_cc * (soc_cc2cv - msoc), 100); + t_predicted_cc *= HOURS_TO_SECONDS; + t_predicted_cc = div_s64(t_predicted_cc, (ibatt_avg + i_cc2cv) / 2); -cv_estimate: - fg_dbg(chip, FG_TTF, "t_predicted_cc=%d\n", t_predicted); +skip_cc_estimate: + fg_dbg(chip, FG_TTF, "t_predicted_cc=%lld\n", t_predicted_cc); - iterm = max(100, abs(chip->dt.sys_term_curr_ma) + 200); - fg_dbg(chip, FG_TTF, "iterm=%d\n", iterm); - - if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER) - tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm); + /* CV estimate starts here */ + if (chip->charge_type >= POWER_SUPPLY_CHARGE_TYPE_TAPER) + ln_val = ibatt_avg / (abs(chip->dt.sys_term_curr_ma) + 200); else - tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm); + ln_val = i_cc2cv / (abs(chip->dt.sys_term_curr_ma) + 200); - rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), tau, &tau); - if (rc < 0) { - pr_err("failed to interpolate tau rc=%d\n", rc); - return rc; - } - - /* tau is scaled linearly from 95% to 100% SOC */ - if (msoc >= 95) - tau = tau * 2 * (100 - msoc) / 10; - - fg_dbg(chip, FG_TTF, "tau=%d\n", tau); - t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau * - HOURS_TO_SECONDS, NANO_UNIT); - fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv); - t_predicted += t_predicted_cv; - - fg_dbg(chip, FG_TTF, "t_predicted_prefilter=%d\n", t_predicted); - if (chip->ttf.last_ms != 0) { - delta_ms = ktime_ms_delta(ktime_get_boottime(), - ms_to_ktime(chip->ttf.last_ms)); - if (delta_ms > 10000) { - ttf_slope = div64_s64( - (s64)(t_predicted - chip->ttf.last_ttf) * - MICRO_UNIT, delta_ms); - if (ttf_slope > -100) - ttf_slope = -100; - else if (ttf_slope < -2000) - ttf_slope = -2000; - - t_predicted = div_s64( - (s64)ttf_slope * delta_ms, MICRO_UNIT) + - chip->ttf.last_ttf; - fg_dbg(chip, FG_TTF, "ttf_slope=%d\n", ttf_slope); - } else { - t_predicted = chip->ttf.last_ttf; - } - } - - /* clamp the ttf to 0 */ - if (t_predicted < 0) - t_predicted = 0; - - fg_dbg(chip, FG_TTF, "t_predicted_postfilter=%d\n", t_predicted); - *val = t_predicted; + if (msoc < 95) + centi_tau_scale = 100; + else + centi_tau_scale = 20 * (100 - msoc); + + fg_dbg(chip, FG_TTF, "ln_in=%d\n", ln_val); + rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), ln_val, &ln_val); + fg_dbg(chip, FG_TTF, "ln_out=%d\n", ln_val); + t_predicted_cv = div_s64((s64)act_cap_uah * rbatt, MICRO_UNIT); + t_predicted_cv = div_s64(t_predicted_cv * centi_tau_scale, 100); + t_predicted_cv = div_s64(t_predicted_cv * ln_val, MILLI_UNIT); + t_predicted_cv = div_s64(t_predicted_cv * HOURS_TO_SECONDS, MICRO_UNIT); + fg_dbg(chip, FG_TTF, "t_predicted_cv=%lld\n", t_predicted_cv); + *val = t_predicted_cc + t_predicted_cv; return 0; } -static int fg_get_time_to_full(struct fg_chip *chip, int *val) -{ - int rc; - - mutex_lock(&chip->ttf.lock); - rc = fg_get_time_to_full_locked(chip, val); - mutex_unlock(&chip->ttf.lock); - return rc; -} - #define CENTI_ICORRECT_C0 105 #define CENTI_ICORRECT_C1 20 static int fg_get_time_to_empty(struct fg_chip *chip, int *val) { - int rc, ibatt_avg, msoc, full_soc, act_cap_mah, divisor; + int rc, ibatt_avg, msoc, act_cap_uah; + s32 divisor; + s64 t_predicted; - rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg); + rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg); if (rc < 0) { /* try to get instantaneous current */ rc = fg_get_battery_current(chip, &ibatt_avg); @@ -3100,36 +3671,31 @@ static int fg_get_time_to_empty(struct fg_chip *chip, int *val) } } - ibatt_avg /= MILLI_UNIT; - /* clamp ibatt_avg to 100mA */ - if (ibatt_avg < 100) - ibatt_avg = 100; + /* clamp ibatt_avg to 150mA */ + if (ibatt_avg < 150000) + ibatt_avg = 150000; - rc = fg_get_prop_capacity(chip, &msoc); - if (rc < 0) { - pr_err("Error in getting capacity, rc=%d\n", rc); - return rc; - } - - rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); + rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah); if (rc < 0) { pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc); return rc; } + act_cap_uah *= MILLI_UNIT; - rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc); + rc = fg_get_prop_capacity(chip, &msoc); if (rc < 0) { - pr_err("failed to get full soc rc=%d\n", rc); + pr_err("Error in getting capacity, rc=%d\n", rc); return rc; } - full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY, - FULL_SOC_RAW); - act_cap_mah = full_soc * act_cap_mah / 100; + t_predicted = div_s64((s64)msoc * act_cap_uah, 100); + t_predicted *= HOURS_TO_SECONDS; divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc; - divisor = ibatt_avg * divisor / 100; - divisor = max(100, divisor); - *val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor; + divisor = div_s64((s64)divisor * ibatt_avg, 10000); + if (divisor > 0) + t_predicted = div_s64(t_predicted, divisor); + + *val = t_predicted; return 0; } @@ -3156,200 +3722,56 @@ static int fg_update_maint_soc(struct fg_chip *chip) chip->maint_soc = 0; } else if (msoc <= chip->last_msoc) { /* MSOC is decreasing. Decrease maintenance SOC as well */ - chip->maint_soc -= 1; - if (!(msoc % 10)) { - /* - * Reduce the maintenance SOC additionally by 1 whenever - * it crosses a SOC multiple of 10. - */ - chip->maint_soc -= 1; - chip->delta_soc -= 1; - } - } - - fg_dbg(chip, FG_IRQ, "msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n", - msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc); - chip->last_msoc = msoc; -out: - mutex_unlock(&chip->charge_full_lock); - return rc; -} - -static int fg_esr_validate(struct fg_chip *chip) -{ - int rc, esr_uohms; - u8 buf[2]; - - if (chip->dt.esr_clamp_mohms <= 0) - return 0; - - rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms); - if (rc < 0) { - pr_err("failed to get ESR, rc=%d\n", rc); - return rc; - } - - if (esr_uohms >= chip->dt.esr_clamp_mohms * 1000) { - pr_debug("ESR %d is > ESR_clamp\n", esr_uohms); - return 0; - } - - esr_uohms = chip->dt.esr_clamp_mohms * 1000; - fg_encode(chip->sp, FG_SRAM_ESR, esr_uohms, buf); - rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR].addr_word, - chip->sp[FG_SRAM_ESR].addr_byte, buf, - chip->sp[FG_SRAM_ESR].len, FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in writing ESR, rc=%d\n", rc); - return rc; - } - - fg_dbg(chip, FG_STATUS, "ESR clamped to %duOhms\n", esr_uohms); - return 0; -} - -static int fg_force_esr_meas(struct fg_chip *chip) -{ - int rc; - int esr_uohms; - - /* force esr extraction enable */ - rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, - ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0), - FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("failed to enable esr extn rc=%d\n", rc); - return rc; - } - - rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip), - LD_REG_CTRL_BIT, 0); - if (rc < 0) { - pr_err("Error in configuring qnovo_cfg rc=%d\n", rc); - return rc; - } - - rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip), - ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT, - ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT); - if (rc < 0) { - pr_err("Error in configuring force ESR rc=%d\n", rc); - return rc; - } - - /* wait 1.5 seconds for hw to measure ESR */ - msleep(1500); - rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip), - ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT, - 0); - if (rc < 0) { - pr_err("Error in restoring force ESR rc=%d\n", rc); - return rc; - } - - rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip), - LD_REG_CTRL_BIT, LD_REG_CTRL_BIT); - if (rc < 0) { - pr_err("Error in restoring qnovo_cfg rc=%d\n", rc); - return rc; - } - - /* force esr extraction disable */ - rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, - ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), 0, - FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("failed to disable esr extn rc=%d\n", rc); - return rc; + chip->maint_soc -= 1; + if (!(msoc % 10)) { + /* + * Reduce the maintenance SOC additionally by 1 whenever + * it crosses a SOC multiple of 10. + */ + chip->maint_soc -= 1; + chip->delta_soc -= 1; + } } - fg_get_battery_resistance(chip, &esr_uohms); - fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms); - + fg_dbg(chip, FG_IRQ, "msoc: %d last_msoc: %d maint_soc: %d delta_soc: %d\n", + msoc, chip->last_msoc, chip->maint_soc, chip->delta_soc); + chip->last_msoc = msoc; +out: + mutex_unlock(&chip->charge_full_lock); return rc; } -static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable) +static int fg_esr_validate(struct fg_chip *chip) { - int rc; + int rc, esr_uohms; + u8 buf[2]; - /* force esr extraction disable when qnovo enables */ - rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD, - ESR_EXTRACTION_ENABLE_OFFSET, - BIT(0), qnovo_enable ? 0 : BIT(0), - FG_IMA_DEFAULT); - if (rc < 0) - pr_err("Error in configuring esr extraction rc=%d\n", rc); + if (chip->dt.esr_clamp_mohms <= 0) + return 0; - rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip), - LD_REG_CTRL_BIT, - qnovo_enable ? LD_REG_CTRL_BIT : 0); + rc = fg_get_sram_prop(chip, FG_SRAM_ESR, &esr_uohms); if (rc < 0) { - pr_err("Error in configuring qnovo_cfg rc=%d\n", rc); + pr_err("failed to get ESR, rc=%d\n", rc); return rc; } - fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n"); - return 0; -} - -static void ttf_work(struct work_struct *work) -{ - struct fg_chip *chip = container_of(work, struct fg_chip, - ttf_work.work); - int rc, ibatt_now, vbatt_now, ttf; - ktime_t ktime_now; - mutex_lock(&chip->ttf.lock); - if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING && - chip->charge_status != POWER_SUPPLY_STATUS_DISCHARGING) - goto end_work; - - rc = fg_get_battery_current(chip, &ibatt_now); - if (rc < 0) { - pr_err("failed to get battery current, rc=%d\n", rc); - goto end_work; + if (esr_uohms >= chip->dt.esr_clamp_mohms * 1000) { + pr_debug("ESR %d is > ESR_clamp\n", esr_uohms); + return 0; } - rc = fg_get_battery_voltage(chip, &vbatt_now); + esr_uohms = chip->dt.esr_clamp_mohms * 1000; + fg_encode(chip->sp, FG_SRAM_ESR, esr_uohms, buf); + rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR].addr_word, + chip->sp[FG_SRAM_ESR].addr_byte, buf, + chip->sp[FG_SRAM_ESR].len, FG_IMA_DEFAULT); if (rc < 0) { - pr_err("failed to get battery voltage, rc=%d\n", rc); - goto end_work; - } - - fg_circ_buf_add(&chip->ttf.ibatt, ibatt_now); - fg_circ_buf_add(&chip->ttf.vbatt, vbatt_now); - - if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) { - rc = fg_get_time_to_full_locked(chip, &ttf); - if (rc < 0) { - pr_err("failed to get ttf, rc=%d\n", rc); - goto end_work; - } - - /* keep the wake lock and prime the IBATT and VBATT buffers */ - if (ttf < 0) { - /* delay for one FG cycle */ - schedule_delayed_work(&chip->ttf_work, - msecs_to_jiffies(1500)); - mutex_unlock(&chip->ttf.lock); - return; - } - - /* update the TTF reference point every minute */ - ktime_now = ktime_get_boottime(); - if (ktime_ms_delta(ktime_now, - ms_to_ktime(chip->ttf.last_ms)) > 60000 || - chip->ttf.last_ms == 0) { - chip->ttf.last_ttf = ttf; - chip->ttf.last_ms = ktime_to_ms(ktime_now); - } + pr_err("Error in writing ESR, rc=%d\n", rc); + return rc; } - /* recurse every 10 seconds */ - schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(10000)); -end_work: - vote(chip->awake_votable, TTF_PRIMING, false, 0); - mutex_unlock(&chip->ttf.lock); + fg_dbg(chip, FG_STATUS, "ESR clamped to %duOhms\n", esr_uohms); + return 0; } /* PSY CALLBACKS STAY HERE */ @@ -3384,7 +3806,15 @@ static int fg_psy_get_property(struct power_supply *psy, rc = fg_get_sram_prop(chip, FG_SRAM_OCV, &pval->intval); break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) pval->intval = chip->cl.nom_cap_uah; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chip->initial_capacity >= 0) + pval->intval = chip->initial_capacity; + else + pval->intval = chip->cl.nom_cap_uah; +#endif break; case POWER_SUPPLY_PROP_RESISTANCE_ID: pval->intval = chip->batt_id_ohms; @@ -3428,20 +3858,14 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval); break; - case POWER_SUPPLY_PROP_CC_STEP: - if ((chip->ttf.cc_step.sel >= 0) && - (chip->ttf.cc_step.sel < MAX_CC_STEPS)) { - pval->intval = - chip->ttf.cc_step.arr[chip->ttf.cc_step.sel]; - } else { - pr_err("cc_step_sel is out of bounds [0, %d]\n", - chip->ttf.cc_step.sel); - return -EINVAL; - } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + case POWER_SUPPLY_PROP_CHARGE_FULL_RAW: + pval->intval = chip->charge_full_raw; break; - case POWER_SUPPLY_PROP_CC_STEP_SEL: - pval->intval = chip->ttf.cc_step.sel; + case POWER_SUPPLY_PROP_TIME_TO_CAP_LEARNING: + pval->intval = chip->cl.learned_time_ms / 1000; break; +#endif default: pr_err("unsupported property %d\n", psp); rc = -EINVAL; @@ -3474,32 +3898,6 @@ static int fg_psy_set_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: rc = fg_set_constant_chg_voltage(chip, pval->intval); break; - case POWER_SUPPLY_PROP_RESISTANCE: - rc = fg_force_esr_meas(chip); - break; - case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE: - rc = fg_prepare_for_qnovo(chip, pval->intval); - break; - case POWER_SUPPLY_PROP_CC_STEP: - if ((chip->ttf.cc_step.sel >= 0) && - (chip->ttf.cc_step.sel < MAX_CC_STEPS)) { - chip->ttf.cc_step.arr[chip->ttf.cc_step.sel] = - pval->intval; - } else { - pr_err("cc_step_sel is out of bounds [0, %d]\n", - chip->ttf.cc_step.sel); - return -EINVAL; - } - break; - case POWER_SUPPLY_PROP_CC_STEP_SEL: - if ((pval->intval >= 0) && (pval->intval < MAX_CC_STEPS)) { - chip->ttf.cc_step.sel = pval->intval; - } else { - pr_err("cc_step_sel is out of bounds [0, %d]\n", - pval->intval); - return -EINVAL; - } - break; default: break; } @@ -3513,8 +3911,6 @@ static int fg_property_is_writeable(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CYCLE_COUNT_ID: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: - case POWER_SUPPLY_PROP_CC_STEP: - case POWER_SUPPLY_PROP_CC_STEP_SEL: return 1; default: break; @@ -3575,8 +3971,10 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, - POWER_SUPPLY_PROP_CC_STEP, - POWER_SUPPLY_PROP_CC_STEP_SEL, +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + POWER_SUPPLY_PROP_CHARGE_FULL_RAW, + POWER_SUPPLY_PROP_TIME_TO_CAP_LEARNING, +#endif }; static const struct power_supply_desc fg_psy_desc = { @@ -3787,7 +4185,8 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } - restore_cycle_counter(chip); + if (chip->cyc_ctr.en) + restore_cycle_counter(chip); if (chip->dt.jeita_hyst_temp >= 0) { val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT; @@ -3861,6 +4260,74 @@ static int fg_hw_init(struct fg_chip *chip) } } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chip->dt.therm_coeff_c1 > 0) { + rc = fg_masked_write(chip, BATT_INFO_THERM_C1(chip), + BATT_INFO_THERM_COEFF_MASK, + chip->dt.therm_coeff_c1); + if (rc < 0) { + pr_err("Error in writing therm_coeff_c1, rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.therm_coeff_c2 > 0) { + rc = fg_masked_write(chip, BATT_INFO_THERM_C2(chip), + BATT_INFO_THERM_COEFF_MASK, + chip->dt.therm_coeff_c2); + if (rc < 0) { + pr_err("Error in writing therm_coeff_c2, rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.therm_coeff_c3 > 0) { + rc = fg_masked_write(chip, BATT_INFO_THERM_C3(chip), + BATT_INFO_THERM_COEFF_MASK, + chip->dt.therm_coeff_c3); + if (rc < 0) { + pr_err("Error in writing therm_coeff_c3, rc=%d\n", rc); + return rc; + } + } + + val = FG_ESR_CURRENT_THR_VALUE; + rc = fg_sram_write(chip, ESR_CURRENT_THR_WORD, ESR_CURRENT_THR_OFFSET, + &val, 1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing ESR current threshold, rc=%d\n", rc); + return rc; + } + + val = KI_COEFF_CUTOFF_VOLT_VALUE; + rc = fg_sram_write(chip, KI_COEFF_CUTOFF_VOLT_WORD, + KI_COEFF_CUTOFF_VOLT_OFFSET, + &val, 1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing KI_COEFF_CUTOFF_VOLT_OFFSET, rc=%d\n", + rc); + return rc; + } + + rc = fg_sram_masked_write(chip, ESR_VCTIBTRSLWEN_WORD, + ESR_VCTIBTRSLWEN_OFFSET, + ESR_VCTIBTRSLWEN_MASK, + ESR_VCTIBTRSLWEN_VALUE, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing ESR_VCTIBTRSLWEN_OFFSET, rc=%d\n", rc); + return rc; + } + + rc = fg_sram_masked_write(chip, SAT_CC_CLR_AUTO_WORD, + SAT_CC_CLR_AUTO_OFFSET, + SAT_CC_CLR_AUTO_MASK, + SAT_CC_CLR_AUTO_VALUE, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing SAT_CC_CLR_AUTO_OFFSET, rc=%d\n", rc); + return rc; + } + +#endif return 0; } @@ -4014,11 +4481,6 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data) if (rc < 0) pr_err("Error in adjusting timebase, rc=%d\n", rc); - rc = fg_adjust_recharge_voltage(chip); - if (rc < 0) - pr_err("Error in adjusting recharge_voltage, rc=%d\n", - rc); - chip->last_batt_temp = batt_temp; power_supply_changed(chip->batt_psy); } @@ -4066,7 +4528,8 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) int rc; fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq); - fg_cycle_counter_update(chip); + if (chip->cyc_ctr.en) + schedule_work(&chip->cycle_count_work); if (chip->cl.active) fg_cap_learning_update(chip); @@ -4654,6 +5117,20 @@ static int fg_parse_dt(struct fg_chip *chip) chip->dt.hold_soc_while_full = of_property_read_bool(node, "qcom,hold-soc-while-full"); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + rc = of_property_read_u32(node, "somc,rated-capacity-uah", &temp); + if (rc < 0) + chip->rated_capacity = -EINVAL; + else + chip->rated_capacity = temp; + + rc = of_property_read_u32(node, "somc,initial-capacity-uah", &temp); + if (rc < 0) + chip->initial_capacity = -EINVAL; + else + chip->initial_capacity = temp; + +#endif rc = fg_parse_ki_coefficients(chip); if (rc < 0) pr_err("Error in parsing Ki coefficients, rc=%d\n", rc); @@ -4723,6 +5200,26 @@ static int fg_parse_dt(struct fg_chip *chip) chip->dt.esr_meas_curr_ma = temp; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + rc = of_property_read_u32(node, "somc,therm-coeff-c1", &temp); + if (rc < 0) + chip->dt.therm_coeff_c1 = -EINVAL; + else + chip->dt.therm_coeff_c1 = temp; + + rc = of_property_read_u32(node, "somc,therm-coeff-c2", &temp); + if (rc < 0) + chip->dt.therm_coeff_c2 = -EINVAL; + else + chip->dt.therm_coeff_c2 = temp; + + rc = of_property_read_u32(node, "somc,therm-coeff-c3", &temp); + if (rc < 0) + chip->dt.therm_coeff_c3 = -EINVAL; + else + chip->dt.therm_coeff_c3 = temp; + +#endif return 0; } @@ -4745,6 +5242,360 @@ static void fg_cleanup(struct fg_chip *chip) dev_set_drvdata(chip->dev, NULL); } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +/***************************** + * somc sysfs implementation * + *****************************/ +enum fg_somc_sysfs { + ATTR_RSLOW = 0, + ATTR_BATTERY_SOC, + ATTR_CC_SOC, + ATTR_SOC_SYSTEM, + ATTR_SOC_MONOTONIC, + ATTR_SOC_CUTOFF, + ATTR_SOC_FULL, + ATTR_SW_CC_SOC, + ATTR_FG_CAPACITY, + ATTR_SOC_INT, + ATTR_BATT_INT, + ATTR_PMIC_SUBTYPE, + ATTR_BATT_INFO, + ATTR_BATT_AGING_LEVEL, + ATTR_RATED_CAPACITY, + ATTR_RECAHRGE_VOLTAGE_MV, + ATTR_CHARGE_FULL, + ATTR_CL_ACTIVE, + ATTR_CL_BSOC_DROP, + ATTR_CL_CCSOC_DROP, + ATTR_CL_HOLD_TIME, + ATTR_CL_TOTAL_TIME, +}; + +static ssize_t fg_somc_param_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t fg_somc_param_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count); + +static struct device_attribute fg_somc_attrs[] = { + __ATTR(rslow, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(battery_soc, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(cc_soc, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(soc_system, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(soc_monotonic, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(soc_cutoff, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(soc_full, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(sw_cc_soc, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(capacity, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(soc_int, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(batt_int, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(pmic_subtype, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(batt_info, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(batt_aging_level, S_IRUGO|S_IWUSR, + fg_somc_param_show, fg_somc_param_store), + __ATTR(rated_capacity, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(recharge_voltage_mv, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(charge_full, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(cl_active, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(cl_bsoc_drop, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(cl_ccsoc_drop, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(cl_hold_time, S_IRUGO, fg_somc_param_show, NULL), + __ATTR(cl_total_time, S_IRUGO, fg_somc_param_show, NULL), +}; + +#define DECIMAL_CELL 100 +#define DECIMAL_MAG 10000LL + +ssize_t fg_somc_get_sram_soc_str(struct fg_chip *chip, + enum fg_sram_param_id id, s64 soc_max_range, s64 soc_lsb, + bool is_signed, char *buf, int size) +{ + int rc = 0; + int value, capacity, high_cap, low_cap; + + rc = fg_get_sram_prop(chip, id, &value); + if (rc < 0) { + pr_err("Error reading address rc=%d\n", rc); + return 0; + } + + if (is_signed) + capacity = (int)(((s64)value * soc_lsb * DECIMAL_MAG) / + soc_max_range); + else + capacity = (int)(((u64)((u32)value) * soc_lsb * DECIMAL_MAG) / + soc_max_range); + + high_cap = capacity / DECIMAL_CELL; + low_cap = abs(capacity % DECIMAL_CELL); + size = scnprintf(buf, size, "%d.%02d", high_cap, low_cap); + return size; +} + +static ssize_t fg_somc_param_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fg_chip *chip = dev_get_drvdata(dev); + ssize_t size = 0; + const ptrdiff_t off = attr - fg_somc_attrs; + int rc = 0; + int val; + u8 reg; + u8 sram_buf_1; + u8 sram_buf_4[4]; + + switch (off) { + case ATTR_RSLOW: + rc = fg_get_sram_prop(chip, FG_SRAM_RSLOW, &val); + if (rc < 0) + pr_err("Error reading address rc=%d\n", rc); + else + size = scnprintf(buf, PAGE_SIZE, "%d\n", val); + break; + case ATTR_BATTERY_SOC: + size = fg_somc_get_sram_soc_str(chip, FG_SRAM_BATT_SOC, + BATT_SOC_MAX_RANGE, BATT_SOC_LSB, + false, buf, PAGE_SIZE); + break; + case ATTR_CC_SOC: + size = fg_somc_get_sram_soc_str(chip, FG_SRAM_CC_SOC, + CC_SOC_MAX_RANGE, CC_SOC_LSB, + true, buf, PAGE_SIZE); + break; + case ATTR_SOC_SYSTEM: + size = fg_somc_get_sram_soc_str(chip, FG_SRAM_SOC_SYSTEM, + SOC_MAX_RANGE, SOC_LSB, + false, buf, PAGE_SIZE); + break; + case ATTR_SOC_MONOTONIC: + size = fg_somc_get_sram_soc_str(chip, FG_SRAM_SOC_MONOTONIC, + SOC_MAX_RANGE, SOC_LSB, + false, buf, PAGE_SIZE); + break; + case ATTR_SOC_CUTOFF: + size = fg_somc_get_sram_soc_str(chip, FG_SRAM_SOC_CUTOFF, + SOC_MAX_RANGE, SOC_LSB, + false, buf, PAGE_SIZE); + break; + case ATTR_SOC_FULL: + size = fg_somc_get_sram_soc_str(chip, FG_SRAM_SOC_FULL, + SOC_MAX_RANGE, SOC_LSB, + false, buf, PAGE_SIZE); + break; + case ATTR_SW_CC_SOC: + size = fg_somc_get_sram_soc_str(chip, FG_SRAM_CC_SOC_SW, + CC_SOC_MAX_RANGE, CC_SOC_LSB, + true, buf, PAGE_SIZE); + break; + case ATTR_FG_CAPACITY: + rc = fg_read(chip, BATT_SOC_FG_MONOTONIC_SOC_CP(chip), ®, 1); + if (rc < 0) + pr_err("Error reading address rc=%d\n", rc); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02x\n", reg); + break; + case ATTR_SOC_INT: + rc = fg_read(chip, BATT_SOC_INT_RT_STS(chip), ®, 1); + if (rc < 0) + pr_err("Error reading address rc=%d\n", rc); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02x\n", reg); + break; + case ATTR_BATT_INT: + rc = fg_read(chip, BATT_INFO_INT_RT_STS(chip), ®, 1); + if (rc < 0) + pr_err("Error reading address rc=%d\n", rc); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02x\n", reg); + break; + case ATTR_PMIC_SUBTYPE: + switch (chip->pmic_rev_id->pmic_subtype) { + case PMI8998_SUBTYPE: + if (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4) + size = scnprintf(buf, PAGE_SIZE, "PMI8998-v1\n"); + else if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4) + size = scnprintf(buf, PAGE_SIZE, "PMI8998-v2\n"); + else + size = scnprintf(buf, PAGE_SIZE, "not supported\n"); + break; + case PM660_SUBTYPE: + size = scnprintf(buf, PAGE_SIZE, "PM660\n"); + break; + default: + size = scnprintf(buf, PAGE_SIZE, "not supported\n"); + } + break; + case ATTR_BATT_INFO: + rc = fg_sram_read(chip, 0, 0, sram_buf_4, 4, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in readging addr 0, rc:%d\n", rc); + break; + } + rc = fg_sram_read(chip, 20, 0, &sram_buf_1, 1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in readging addr 20, rc:%d\n", rc); + break; + } + size = scnprintf(buf, PAGE_SIZE, + "%s/%d/%d/%02x %02x %02x %02x|%02x\n", + fg_get_battery_type(chip), + chip->batt_id_ohms, + chip->batt_aging_level, + sram_buf_4[0], + sram_buf_4[1], + sram_buf_4[2], + sram_buf_4[3], + sram_buf_1); + break; + case ATTR_BATT_AGING_LEVEL: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + chip->batt_aging_level); + break; + case ATTR_RATED_CAPACITY: + if (chip->rated_capacity >= 0) + size = scnprintf(buf, PAGE_SIZE, "%d\n", + chip->rated_capacity); + else + size = scnprintf(buf, PAGE_SIZE, "%d\n", + (int)chip->cl.nom_cap_uah); + break; + case ATTR_RECAHRGE_VOLTAGE_MV: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + chip->recharge_voltage_mv); + break; + case ATTR_CHARGE_FULL: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + (int)chip->charge_full); + break; + case ATTR_CL_ACTIVE: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + (int)chip->cl.active); + break; + case ATTR_CL_BSOC_DROP: + val = (int)((u64)chip->cl.batt_soc_drop + * BATT_SOC_LSB * DECIMAL_MAG + / BATT_SOC_MAX_RANGE); + size = scnprintf(buf, PAGE_SIZE, "%d.%02d", + val / DECIMAL_CELL, val % DECIMAL_CELL); + break; + case ATTR_CL_CCSOC_DROP: + val = (int)((u64)chip->cl.cc_soc_drop + * CC_SOC_LSB * DECIMAL_MAG + / CC_SOC_MAX_RANGE); + size = scnprintf(buf, PAGE_SIZE, "%d.%02d", + val / DECIMAL_CELL, val % DECIMAL_CELL); + break; + case ATTR_CL_HOLD_TIME: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + (int)(chip->cl.hold_time / 1000)); + break; + case ATTR_CL_TOTAL_TIME: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + (int)(chip->cl.total_time / 1000)); + break; + default: + size = 0; + break; + } + return size; +} + +static int fg_somc_set_batt_aging_level(struct fg_chip *chip, const char *buf) +{ + int rc, msoc; + + rc = kstrtoint(buf, 10, &chip->batt_aging_level); + if (rc < 0) { + pr_err("Error in batt aging level being invalid, rc:%d\n", rc); + goto err; + } + + if (chip->batt_aging_level == chip->saved_batt_aging_level) + return 0; + + rc = fg_get_prop_capacity(chip, &msoc); + if (rc < 0) { + pr_err("Error in getting capacity, rc=%d\n", rc); + goto err; + } + + chip->last_soc = msoc; + chip->profile_loaded = false; + schedule_delayed_work(&chip->profile_load_work, 0); + return 0; + +err: + chip->batt_aging_level = chip->saved_batt_aging_level; + return -EINVAL; +} + +static void fg_somc_restore_batt_aging_level(struct fg_chip *chip) +{ + int rc; + u8 val; + + rc = fg_sram_read(chip, BATT_AGING_LEVEL_WORD, + BATT_AGING_LEVEL_OFFSET, &val, 1, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("failed to read batt aging level rc=%d\n", rc); + chip->saved_batt_aging_level = 0; + } else { + chip->saved_batt_aging_level = val; + } + + chip->batt_aging_level = chip->saved_batt_aging_level; +} + +static ssize_t fg_somc_param_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fg_chip *chip = dev_get_drvdata(dev); + const ptrdiff_t off = attr - fg_somc_attrs; + int rc; + + switch (off) { + case ATTR_BATT_AGING_LEVEL: + rc = fg_somc_set_batt_aging_level(chip, buf); + if (rc < 0) + count = 0; + + break; + default: + break; + } + + return count; +} + +static int fg_somc_create_sysfs_entries(struct device *dev) +{ + int i; + int rc = 0; + + for (i = 0; i < ARRAY_SIZE(fg_somc_attrs); i++) { + rc = device_create_file(dev, &fg_somc_attrs[i]); + if (rc < 0) { + dev_err(dev, "device_create_file failed rc = %d\n", rc); + goto revert; + } + } + return 0; +revert: + for (i = i - 1; i >= 0; i--) + device_remove_file(dev, &fg_somc_attrs[i]); + return rc; +} + +static void fg_somc_remove_sysfs_entries(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fg_somc_attrs); i++) + device_remove_file(dev, &fg_somc_attrs[i]); +} + +#endif static int fg_gen3_probe(struct platform_device *pdev) { struct fg_chip *chip; @@ -4761,7 +5612,6 @@ static int fg_gen3_probe(struct platform_device *pdev) chip->charge_status = -EINVAL; chip->prev_charge_status = -EINVAL; chip->ki_coeff_full_soc = -EINVAL; - chip->online_status = -EINVAL; chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { dev_err(chip->dev, "Parent regmap is unavailable\n"); @@ -4830,13 +5680,14 @@ static int fg_gen3_probe(struct platform_device *pdev) mutex_init(&chip->sram_rw_lock); mutex_init(&chip->cyc_ctr.lock); mutex_init(&chip->cl.lock); - mutex_init(&chip->ttf.lock); + mutex_init(&chip->batt_avg_lock); mutex_init(&chip->charge_full_lock); init_completion(&chip->soc_update); init_completion(&chip->soc_ready); INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work); INIT_WORK(&chip->status_change_work, status_change_work); - INIT_DELAYED_WORK(&chip->ttf_work, ttf_work); + INIT_WORK(&chip->cycle_count_work, cycle_count_work); + INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work); INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work); rc = fg_memif_init(chip); @@ -4846,6 +5697,9 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + fg_somc_restore_batt_aging_level(chip); +#endif rc = fg_hw_init(chip); if (rc < 0) { dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n", @@ -4899,6 +5753,17 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + rc = fg_somc_create_sysfs_entries(chip->dev); + if (rc < 0) { + dev_err(chip->dev, + "Error in creating fg_somc_sysfs entries, rc:%d\n", + rc); + goto exit; + } + +#endif + rc = fg_get_battery_voltage(chip, &volt_uv); if (!rc) rc = fg_get_prop_capacity(chip, &msoc); @@ -4933,7 +5798,7 @@ static int fg_gen3_suspend(struct device *dev) if (rc < 0) pr_err("Error in configuring ESR timer, rc=%d\n", rc); - cancel_delayed_work_sync(&chip->ttf_work); + cancel_delayed_work_sync(&chip->batt_avg_work); if (fg_sram_dump) cancel_delayed_work_sync(&chip->sram_dump_work); return 0; @@ -4948,7 +5813,9 @@ static int fg_gen3_resume(struct device *dev) if (rc < 0) pr_err("Error in configuring ESR timer, rc=%d\n", rc); - schedule_delayed_work(&chip->ttf_work, 0); + fg_circ_buf_clr(&chip->ibatt_circ_buf); + fg_circ_buf_clr(&chip->vbatt_circ_buf); + schedule_delayed_work(&chip->batt_avg_work, 0); if (fg_sram_dump) schedule_delayed_work(&chip->sram_dump_work, msecs_to_jiffies(fg_sram_dump_period_ms)); @@ -4964,6 +5831,9 @@ static int fg_gen3_remove(struct platform_device *pdev) { struct fg_chip *chip = dev_get_drvdata(&pdev->dev); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + fg_somc_remove_sysfs_entries(chip->dev); +#endif fg_cleanup(chip); return 0; } diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c index 53af3415ec6aa2f3b99c1d93d37c5d43bc031787..eb97eb0ff2ac5476a0ad54be7604371e58b820a9 100644 --- a/drivers/power/supply/qcom/qpnp-qnovo.c +++ b/drivers/power/supply/qcom/qpnp-qnovo.c @@ -20,7 +20,6 @@ #include #include #include -#include #define QNOVO_REVISION1 0x00 #define QNOVO_REVISION2 0x01 @@ -112,26 +111,13 @@ #define GAIN_LSB_FACTOR 976560 #define USER_VOTER "user_voter" -#define SHUTDOWN_VOTER "user_voter" #define OK_TO_QNOVO_VOTER "ok_to_qnovo_voter" #define QNOVO_VOTER "qnovo_voter" -#define FG_AVAILABLE_VOTER "FG_AVAILABLE_VOTER" -#define QNOVO_OVERALL_VOTER "QNOVO_OVERALL_VOTER" -#define QNI_PT_VOTER "QNI_PT_VOTER" -#define ESR_VOTER "ESR_VOTER" - -#define HW_OK_TO_QNOVO_VOTER "HW_OK_TO_QNOVO_VOTER" -#define CHG_READY_VOTER "CHG_READY_VOTER" -#define USB_READY_VOTER "USB_READY_VOTER" -#define DC_READY_VOTER "DC_READY_VOTER" - -#define PT_RESTART_VOTER "PT_RESTART_VOTER" struct qnovo_dt_props { bool external_rsense; struct device_node *revid_dev_node; - bool enable_for_dc; }; struct qnovo { @@ -141,10 +127,6 @@ struct qnovo { struct qnovo_dt_props dt; struct device *dev; struct votable *disable_votable; - struct votable *pt_dis_votable; - struct votable *not_ok_to_qnovo_votable; - struct votable *chg_ready_votable; - struct votable *awake_votable; struct class qnovo_class; struct pmic_revid_data *pmic_rev_id; u32 wa_flags; @@ -156,18 +138,10 @@ struct qnovo { s64 v_gain_mega; struct notifier_block nb; struct power_supply *batt_psy; - struct power_supply *bms_psy; - struct power_supply *usb_psy; - struct power_supply *dc_psy; struct work_struct status_change_work; int fv_uV_request; int fcc_uA_request; - int usb_present; - int dc_present; - struct delayed_work usb_debounce_work; - struct delayed_work dc_debounce_work; - - struct delayed_work ptrain_restart_work; + bool ok_to_qnovo; }; static int debug_mask; @@ -255,39 +229,6 @@ static bool is_batt_available(struct qnovo *chip) return true; } -static bool is_fg_available(struct qnovo *chip) -{ - if (!chip->bms_psy) - chip->bms_psy = power_supply_get_by_name("bms"); - - if (!chip->bms_psy) - return false; - - return true; -} - -static bool is_usb_available(struct qnovo *chip) -{ - if (!chip->usb_psy) - chip->usb_psy = power_supply_get_by_name("usb"); - - if (!chip->usb_psy) - return false; - - return true; -} - -static bool is_dc_available(struct qnovo *chip) -{ - if (!chip->dc_psy) - chip->dc_psy = power_supply_get_by_name("dc"); - - if (!chip->dc_psy) - return false; - - return true; -} - static int qnovo_batt_psy_update(struct qnovo *chip, bool disable) { union power_supply_propval pval = {0}; @@ -340,86 +281,10 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable, return -EINVAL; } - /* - * fg must be available for enable FG_AVAILABLE_VOTER - * won't enable it otherwise - */ - - if (is_fg_available(chip)) - power_supply_set_property(chip->bms_psy, - POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, - &pval); - - vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, disable, 0); rc = qnovo_batt_psy_update(chip, disable); return rc; } -static int pt_dis_votable_cb(struct votable *votable, void *data, int disable, - const char *client) -{ - struct qnovo *chip = data; - int rc; - - if (disable) { - cancel_delayed_work_sync(&chip->ptrain_restart_work); - vote(chip->awake_votable, PT_RESTART_VOTER, false, 0); - } - - rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, - (bool)disable ? 0 : QNOVO_PTRAIN_EN_BIT); - if (rc < 0) { - dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n", - (bool)disable ? "disable" : "enable", rc); - return rc; - } - - if (!disable) { - vote(chip->awake_votable, PT_RESTART_VOTER, true, 0); - schedule_delayed_work(&chip->ptrain_restart_work, - msecs_to_jiffies(20)); - } - - return 0; -} - -static int not_ok_to_qnovo_cb(struct votable *votable, void *data, - int not_ok_to_qnovo, - const char *client) -{ - struct qnovo *chip = data; - - vote(chip->disable_votable, OK_TO_QNOVO_VOTER, not_ok_to_qnovo, 0); - if (not_ok_to_qnovo) - vote(chip->disable_votable, USER_VOTER, true, 0); - - kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); - return 0; -} - -static int chg_ready_cb(struct votable *votable, void *data, int ready, - const char *client) -{ - struct qnovo *chip = data; - - vote(chip->not_ok_to_qnovo_votable, CHG_READY_VOTER, !ready, 0); - - return 0; -} - -static int awake_cb(struct votable *votable, void *data, int awake, - const char *client) -{ - struct qnovo *chip = data; - - if (awake) - pm_stay_awake(chip->dev); - else - pm_relax(chip->dev); - - return 0; -} - static int qnovo_parse_dt(struct qnovo *chip) { struct device_node *node = chip->dev->of_node; @@ -444,8 +309,6 @@ static int qnovo_parse_dt(struct qnovo *chip) pr_err("Missing qcom,pmic-revid property - driver failed\n"); return -EINVAL; } - chip->dt.enable_for_dc = of_property_read_bool(node, - "qcom,enable-for-dc"); return 0; } @@ -763,9 +626,8 @@ static ssize_t ok_to_qnovo_show(struct class *c, struct class_attribute *attr, char *buf) { struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); - int val = get_effective_result(chip->not_ok_to_qnovo_votable); - return snprintf(buf, PAGE_SIZE, "%d\n", !val); + return snprintf(buf, PAGE_SIZE, "%d\n", chip->ok_to_qnovo); } static ssize_t qnovo_enable_show(struct class *c, struct class_attribute *attr, @@ -794,10 +656,21 @@ static ssize_t qnovo_enable_store(struct class *c, struct class_attribute *attr, static ssize_t pt_enable_show(struct class *c, struct class_attribute *attr, char *ubuf) { + int i = attr - qnovo_attributes; struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); - int val = get_effective_result(chip->pt_dis_votable); + u8 buf[2] = {0, 0}; + u16 regval; + int rc; - return snprintf(ubuf, PAGE_SIZE, "%d\n", !val); + rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't read %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + regval = buf[1] << 8 | buf[0]; + + return snprintf(ubuf, PAGE_SIZE, "%d\n", + (int)(regval & QNOVO_PTRAIN_EN_BIT)); } static ssize_t pt_enable_store(struct class *c, struct class_attribute *attr, @@ -805,12 +678,21 @@ static ssize_t pt_enable_store(struct class *c, struct class_attribute *attr, { struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); unsigned long val; + int rc = 0; + + if (get_effective_result(chip->disable_votable)) + return -EINVAL; if (kstrtoul(ubuf, 0, &val)) return -EINVAL; - /* val being 0, userspace wishes to disable pt so vote true */ - vote(chip->pt_dis_votable, QNI_PT_VOTER, val ? false : true, 0); + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, + (bool)val ? QNOVO_PTRAIN_EN_BIT : 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n", + (bool)val ? "enable" : "disable", rc); + return rc; + } return count; } @@ -1234,170 +1116,41 @@ static int qnovo_update_status(struct qnovo *chip) { u8 val = 0; int rc; - bool hw_ok_to_qnovo; + bool ok_to_qnovo; + bool changed = false; rc = qnovo_read(chip, QNOVO_ERROR_STS2, &val, 1); if (rc < 0) { pr_err("Couldn't read error sts rc = %d\n", rc); - hw_ok_to_qnovo = false; + ok_to_qnovo = false; } else { /* * For CV mode keep qnovo enabled, userspace is expected to * disable it after few runs */ - hw_ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ? - true : false; + ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ? true : false; } - vote(chip->not_ok_to_qnovo_votable, HW_OK_TO_QNOVO_VOTER, - !hw_ok_to_qnovo, 0); - return 0; -} - -static void usb_debounce_work(struct work_struct *work) -{ - struct qnovo *chip = container_of(work, - struct qnovo, usb_debounce_work.work); + if (chip->ok_to_qnovo ^ ok_to_qnovo) { - vote(chip->chg_ready_votable, USB_READY_VOTER, true, 0); - vote(chip->awake_votable, USB_READY_VOTER, false, 0); -} + vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !ok_to_qnovo, 0); + if (!ok_to_qnovo) + vote(chip->disable_votable, USER_VOTER, true, 0); -static void dc_debounce_work(struct work_struct *work) -{ - struct qnovo *chip = container_of(work, - struct qnovo, dc_debounce_work.work); + chip->ok_to_qnovo = ok_to_qnovo; + changed = true; + } - vote(chip->chg_ready_votable, DC_READY_VOTER, true, 0); - vote(chip->awake_votable, DC_READY_VOTER, false, 0); + return changed; } -#define DEBOUNCE_MS 15000 /* 15 seconds */ static void status_change_work(struct work_struct *work) { struct qnovo *chip = container_of(work, struct qnovo, status_change_work); - union power_supply_propval pval; - bool usb_present = false, dc_present = false; - int rc; - - if (is_fg_available(chip)) - vote(chip->disable_votable, FG_AVAILABLE_VOTER, false, 0); - - if (is_usb_available(chip)) { - rc = power_supply_get_property(chip->usb_psy, - POWER_SUPPLY_PROP_PRESENT, &pval); - usb_present = (rc < 0) ? 0 : pval.intval; - } - - if (chip->usb_present && !usb_present) { - /* removal */ - chip->usb_present = 0; - cancel_delayed_work_sync(&chip->usb_debounce_work); - vote(chip->awake_votable, USB_READY_VOTER, false, 0); - vote(chip->chg_ready_votable, USB_READY_VOTER, false, 0); - } else if (!chip->usb_present && usb_present) { - /* insertion */ - chip->usb_present = 1; - vote(chip->awake_votable, USB_READY_VOTER, true, 0); - schedule_delayed_work(&chip->usb_debounce_work, - msecs_to_jiffies(DEBOUNCE_MS)); - } - - if (is_dc_available(chip)) { - rc = power_supply_get_property(chip->dc_psy, - POWER_SUPPLY_PROP_PRESENT, - &pval); - dc_present = (rc < 0) ? 0 : pval.intval; - } - if (usb_present) - dc_present = 0; - - /* disable qnovo for dc path by forcing dc_present = 0 always */ - if (!chip->dt.enable_for_dc) - dc_present = 0; - - if (chip->dc_present && !dc_present) { - /* removal */ - chip->dc_present = 0; - cancel_delayed_work_sync(&chip->dc_debounce_work); - vote(chip->awake_votable, DC_READY_VOTER, false, 0); - vote(chip->chg_ready_votable, DC_READY_VOTER, false, 0); - } else if (!chip->dc_present && dc_present) { - /* insertion */ - chip->dc_present = 1; - vote(chip->awake_votable, DC_READY_VOTER, true, 0); - schedule_delayed_work(&chip->dc_debounce_work, - msecs_to_jiffies(DEBOUNCE_MS)); - } - - qnovo_update_status(chip); -} - -static void ptrain_restart_work(struct work_struct *work) -{ - struct qnovo *chip = container_of(work, - struct qnovo, ptrain_restart_work.work); - u8 pt_t1, pt_t2; - int rc; - u8 pt_en; - - rc = qnovo_read(chip, QNOVO_PTRAIN_EN, &pt_en, 1); - if (rc < 0) { - dev_err(chip->dev, "Couldn't read QNOVO_PTRAIN_EN rc = %d\n", - rc); - goto clean_up; - } - - if (!pt_en) { - rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, - QNOVO_PTRAIN_EN_BIT, QNOVO_PTRAIN_EN_BIT); - if (rc < 0) { - dev_err(chip->dev, "Couldn't enable pulse train rc=%d\n", - rc); - goto clean_up; - } - /* sleep 20ms for the pulse trains to restart and settle */ - msleep(20); - } - - rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t1, 1); - if (rc < 0) { - dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n", - rc); - goto clean_up; - } - - /* pttime increments every 2 seconds */ - msleep(2100); - - rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t2, 1); - if (rc < 0) { - dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n", - rc); - goto clean_up; - } - - if (pt_t1 != pt_t2) - goto clean_up; - - /* Toggle pt enable to restart pulse train */ - rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, 0); - if (rc < 0) { - dev_err(chip->dev, "Couldn't disable pulse train rc=%d\n", rc); - goto clean_up; - } - msleep(1000); - rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, - QNOVO_PTRAIN_EN_BIT); - if (rc < 0) { - dev_err(chip->dev, "Couldn't enable pulse train rc=%d\n", rc); - goto clean_up; - } - -clean_up: - vote(chip->awake_votable, PT_RESTART_VOTER, false, 0); + if (qnovo_update_status(chip)) + kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); } static int qnovo_notifier_call(struct notifier_block *nb, @@ -1409,10 +1162,7 @@ static int qnovo_notifier_call(struct notifier_block *nb, if (ev != PSY_EVENT_PROP_CHANGED) return NOTIFY_OK; - if (strcmp(psy->desc->name, "battery") == 0 - || strcmp(psy->desc->name, "bms") == 0 - || strcmp(psy->desc->name, "usb") == 0 - || strcmp(psy->desc->name, "dc") == 0) + if (strcmp(psy->desc->name, "battery") == 0) schedule_work(&chip->status_change_work); return NOTIFY_OK; @@ -1421,27 +1171,8 @@ static int qnovo_notifier_call(struct notifier_block *nb, static irqreturn_t handle_ptrain_done(int irq, void *data) { struct qnovo *chip = data; - union power_supply_propval pval = {0}; qnovo_update_status(chip); - - /* - * hw resets pt_en bit once ptrain_done triggers. - * vote on behalf of QNI to disable it such that - * once QNI enables it, the votable state changes - * and the callback that sets it is indeed invoked - */ - vote(chip->pt_dis_votable, QNI_PT_VOTER, true, 0); - - vote(chip->pt_dis_votable, ESR_VOTER, true, 0); - if (is_fg_available(chip) - && !get_client_vote(chip->disable_votable, USER_VOTER) - && !get_effective_result(chip->not_ok_to_qnovo_votable)) - power_supply_set_property(chip->bms_psy, - POWER_SUPPLY_PROP_RESISTANCE, - &pval); - - vote(chip->pt_dis_votable, ESR_VOTER, false, 0); kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); return IRQ_HANDLED; } @@ -1454,15 +1185,7 @@ static int qnovo_hw_init(struct qnovo *chip) u8 vadc_offset, vadc_gain; u8 val; - vote(chip->chg_ready_votable, USB_READY_VOTER, false, 0); - vote(chip->chg_ready_votable, DC_READY_VOTER, false, 0); - vote(chip->disable_votable, USER_VOTER, true, 0); - vote(chip->disable_votable, FG_AVAILABLE_VOTER, true, 0); - - vote(chip->pt_dis_votable, QNI_PT_VOTER, true, 0); - vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, true, 0); - vote(chip->pt_dis_votable, ESR_VOTER, false, 0); val = 0; rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1); @@ -1626,45 +1349,12 @@ static int qnovo_probe(struct platform_device *pdev) goto cleanup; } - chip->pt_dis_votable = create_votable("QNOVO_PT_DIS", VOTE_SET_ANY, - pt_dis_votable_cb, chip); - if (IS_ERR(chip->pt_dis_votable)) { - rc = PTR_ERR(chip->pt_dis_votable); - goto destroy_disable_votable; - } - - chip->not_ok_to_qnovo_votable = create_votable("QNOVO_NOT_OK", - VOTE_SET_ANY, - not_ok_to_qnovo_cb, chip); - if (IS_ERR(chip->not_ok_to_qnovo_votable)) { - rc = PTR_ERR(chip->not_ok_to_qnovo_votable); - goto destroy_pt_dis_votable; - } - - chip->chg_ready_votable = create_votable("QNOVO_CHG_READY", - VOTE_SET_ANY, - chg_ready_cb, chip); - if (IS_ERR(chip->chg_ready_votable)) { - rc = PTR_ERR(chip->chg_ready_votable); - goto destroy_not_ok_to_qnovo_votable; - } - - chip->awake_votable = create_votable("QNOVO_AWAKE", VOTE_SET_ANY, - awake_cb, chip); - if (IS_ERR(chip->awake_votable)) { - rc = PTR_ERR(chip->awake_votable); - goto destroy_chg_ready_votable; - } - INIT_WORK(&chip->status_change_work, status_change_work); - INIT_DELAYED_WORK(&chip->dc_debounce_work, dc_debounce_work); - INIT_DELAYED_WORK(&chip->usb_debounce_work, usb_debounce_work); - INIT_DELAYED_WORK(&chip->ptrain_restart_work, ptrain_restart_work); rc = qnovo_hw_init(chip); if (rc < 0) { pr_err("Couldn't initialize hardware rc=%d\n", rc); - goto destroy_awake_votable; + goto destroy_votable; } rc = qnovo_register_notifier(chip); @@ -1700,15 +1390,7 @@ static int qnovo_probe(struct platform_device *pdev) unreg_notifier: power_supply_unreg_notifier(&chip->nb); -destroy_awake_votable: - destroy_votable(chip->awake_votable); -destroy_chg_ready_votable: - destroy_votable(chip->chg_ready_votable); -destroy_not_ok_to_qnovo_votable: - destroy_votable(chip->not_ok_to_qnovo_votable); -destroy_pt_dis_votable: - destroy_votable(chip->pt_dis_votable); -destroy_disable_votable: +destroy_votable: destroy_votable(chip->disable_votable); cleanup: platform_set_drvdata(pdev, NULL); @@ -1721,21 +1403,11 @@ static int qnovo_remove(struct platform_device *pdev) class_unregister(&chip->qnovo_class); power_supply_unreg_notifier(&chip->nb); - destroy_votable(chip->chg_ready_votable); - destroy_votable(chip->not_ok_to_qnovo_votable); - destroy_votable(chip->pt_dis_votable); destroy_votable(chip->disable_votable); platform_set_drvdata(pdev, NULL); return 0; } -static void qnovo_shutdown(struct platform_device *pdev) -{ - struct qnovo *chip = platform_get_drvdata(pdev); - - vote(chip->not_ok_to_qnovo_votable, SHUTDOWN_VOTER, true, 0); -} - static const struct of_device_id match_table[] = { { .compatible = "qcom,qpnp-qnovo", }, { }, @@ -1749,7 +1421,6 @@ static struct platform_driver qnovo_driver = { }, .probe = qnovo_probe, .remove = qnovo_remove, - .shutdown = qnovo_shutdown, }; module_platform_driver(qnovo_driver); diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index c085256a794ab0ce3091a19cec50d8f1071d4c37..a319e3931cf301c7798fbbfdb3254a55139409d9 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -19,11 +24,14 @@ #include #include #include -#include #include #include #include #include +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#include +#include +#endif #include "smb-reg.h" #include "smb-lib.h" #include "storm-watch.h" @@ -123,6 +131,87 @@ static struct smb_params v1_params = { .max_u = 1575000, .step_u = 25000, }, + .step_soc_threshold[0] = { + .name = "step charge soc threshold 1", + .reg = STEP_CHG_SOC_OR_BATT_V_TH1_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + }, + .step_soc_threshold[1] = { + .name = "step charge soc threshold 2", + .reg = STEP_CHG_SOC_OR_BATT_V_TH2_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + }, + .step_soc_threshold[2] = { + .name = "step charge soc threshold 3", + .reg = STEP_CHG_SOC_OR_BATT_V_TH3_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + }, + .step_soc_threshold[3] = { + .name = "step charge soc threshold 4", + .reg = STEP_CHG_SOC_OR_BATT_V_TH4_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + }, + .step_soc = { + .name = "step charge soc", + .reg = STEP_CHG_SOC_VBATT_V_REG, + .min_u = 0, + .max_u = 100, + .step_u = 1, + .set_proc = smblib_mapping_soc_from_field_value, + }, + .step_cc_delta[0] = { + .name = "step charge current delta 1", + .reg = STEP_CHG_CURRENT_DELTA1_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, + .step_cc_delta[1] = { + .name = "step charge current delta 2", + .reg = STEP_CHG_CURRENT_DELTA2_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, + .step_cc_delta[2] = { + .name = "step charge current delta 3", + .reg = STEP_CHG_CURRENT_DELTA3_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, + .step_cc_delta[3] = { + .name = "step charge current delta 4", + .reg = STEP_CHG_CURRENT_DELTA4_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, + .step_cc_delta[4] = { + .name = "step charge current delta 5", + .reg = STEP_CHG_CURRENT_DELTA5_REG, + .min_u = 100000, + .max_u = 3200000, + .step_u = 100000, + .get_proc = smblib_mapping_cc_delta_to_field_value, + .set_proc = smblib_mapping_cc_delta_from_field_value, + }, .freq_buck = { .name = "buck switching frequency", .reg = CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG, @@ -156,6 +245,7 @@ static struct smb_params pm660_params = { }, }; +#define STEP_CHARGING_MAX_STEPS 5 struct smb_dt_props { int usb_icl_ua; int dc_icl_ua; @@ -163,13 +253,14 @@ struct smb_dt_props { int wipower_max_uw; int min_freq_khz; int max_freq_khz; + u32 step_soc_threshold[STEP_CHARGING_MAX_STEPS - 1]; + s32 step_cc_delta[STEP_CHARGING_MAX_STEPS]; struct device_node *revid_dev_node; int float_option; int chg_inhibit_thr_mv; bool no_battery; bool hvdcp_disable; bool auto_recharge_soc; - int wd_bark_time; }; struct smb2 { @@ -179,7 +270,13 @@ struct smb2 { bool bad_part; }; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) static int __debug_mask; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +static int __debug_mask = + PR_SOMC; +#endif module_param_named( debug_mask, __debug_mask, int, S_IRUSR | S_IWUSR ); @@ -191,11 +288,6 @@ module_param_named( #define MICRO_1P5A 1500000 #define MICRO_P1A 100000 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50 -#define MIN_WD_BARK_TIME 16 -#define DEFAULT_WD_BARK_TIME 64 -#define BITE_WDOG_TIMEOUT_8S 0x3 -#define BARK_WDOG_TIMEOUT_MASK GENMASK(3, 2) -#define BARK_WDOG_TIMEOUT_SHIFT 2 static int smb2_parse_dt(struct smb2 *chip) { struct smb_charger *chg = &chip->chg; @@ -207,16 +299,27 @@ static int smb2_parse_dt(struct smb2 *chip) return -EINVAL; } - chg->step_chg_enabled = of_property_read_bool(node, - "qcom,step-charging-enable"); + chg->step_chg_enabled = true; - chg->sw_jeita_enabled = of_property_read_bool(node, - "qcom,sw-jeita-enable"); + if (of_property_count_u32_elems(node, "qcom,step-soc-thresholds") + != STEP_CHARGING_MAX_STEPS - 1) + chg->step_chg_enabled = false; - rc = of_property_read_u32(node, "qcom,wd-bark-time-secs", - &chip->dt.wd_bark_time); - if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME) - chip->dt.wd_bark_time = DEFAULT_WD_BARK_TIME; + rc = of_property_read_u32_array(node, "qcom,step-soc-thresholds", + chip->dt.step_soc_threshold, + STEP_CHARGING_MAX_STEPS - 1); + if (rc < 0) + chg->step_chg_enabled = false; + + if (of_property_count_u32_elems(node, "qcom,step-current-deltas") + != STEP_CHARGING_MAX_STEPS) + chg->step_chg_enabled = false; + + rc = of_property_read_u32_array(node, "qcom,step-current-deltas", + chip->dt.step_cc_delta, + STEP_CHARGING_MAX_STEPS); + if (rc < 0) + chg->step_chg_enabled = false; chip->dt.no_battery = of_property_read_bool(node, "qcom,batteryless-platform"); @@ -236,6 +339,17 @@ static int smb2_parse_dt(struct smb2 *chip) if (rc < 0) chip->dt.usb_icl_ua = -EINVAL; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + rc = of_property_read_u32(node, + "somc,product-icl-ua", &chg->product_icl_ua); + if (rc < 0) + chg->product_icl_ua = -EINVAL; + + rc = of_property_read_u32(node, + "somc,high-voltage-icl-ua", &chg->high_voltage_icl_ua); + if (rc < 0) + chg->high_voltage_icl_ua = -EINVAL; +#endif rc = of_property_read_u32(node, "qcom,otg-cl-ua", &chg->otg_cl_ua); if (rc < 0) @@ -269,6 +383,7 @@ static int smb2_parse_dt(struct smb2 *chip) if (rc < 0) chip->dt.wipower_max_uw = -EINVAL; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) { chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len, GFP_KERNEL); @@ -287,6 +402,69 @@ static int smb2_parse_dt(struct smb2 *chip) return rc; } } +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (of_find_property(node, "somc,thermal-fcc-ua", &byte_len)) { + chg->thermal_fcc_ua = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_fcc_ua == NULL) + return -ENOMEM; + + chg->thermal_fcc_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "somc,thermal-fcc-ua", + chg->thermal_fcc_ua, + chg->thermal_fcc_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } else { + pr_err("Coudn't find thermal-fcc-ua table\n"); + } + if (of_find_property(node, "somc,thermal-lo-volt-icl-ua", &byte_len)) { + chg->thermal_lo_volt_icl_ua = devm_kzalloc(chg->dev, + byte_len, GFP_KERNEL); + + if (chg->thermal_lo_volt_icl_ua == NULL) + return -ENOMEM; + + chg->thermal_lo_volt_icl_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "somc,thermal-lo-volt-icl-ua", + chg->thermal_lo_volt_icl_ua, + chg->thermal_lo_volt_icl_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } else { + pr_err("Coudn't find thermal-lo-volt-icl-ua table\n"); + } + if (of_find_property(node, "somc,thermal-hi-volt-icl-ua", &byte_len)) { + chg->thermal_hi_volt_icl_ua = devm_kzalloc(chg->dev, + byte_len, GFP_KERNEL); + + if (chg->thermal_hi_volt_icl_ua == NULL) + return -ENOMEM; + + chg->thermal_hi_volt_icl_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "somc,thermal-hi-volt-icl-ua", + chg->thermal_hi_volt_icl_ua, + chg->thermal_hi_volt_icl_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } else { + pr_err("Coudn't find thermal-hi-volt-icl-ua table\n"); + } +#endif of_property_read_u32(node, "qcom,float-option", &chip->dt.float_option); if (chip->dt.float_option < 0 || chip->dt.float_option > 4) { @@ -320,6 +498,67 @@ static int smb2_parse_dt(struct smb2 *chip) if (rc < 0) chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* USB_SWITCH_SEL */ + chg->usb_switch_sel_gpio = + of_get_named_gpio(node, "usb_switch_sel", 0); + if (!gpio_is_valid(chg->usb_switch_sel_gpio)) { + pr_err("usb_switch_sel_gpio is not available\n"); + return -EINVAL; + } + + chg->jeita_sw_ctl_en = of_property_read_bool(node, + "somc,jeita-sw-ctrl-en"); + chg->jeita_use_aux = of_property_read_bool(node, + "somc,jeita-use-aux-therm"); + + if (chg->jeita_sw_ctl_en) { + /* fcc limitation for JEITA */ + rc = of_property_read_u32(node, "somc,jeita-warm-fcc-ua", + &chg->jeita_warm_fcc_ua); + if (rc < 0) + chg->jeita_warm_fcc_ua = -EINVAL; + + rc = of_property_read_u32(node, "somc,jeita-cool-fcc-ua", + &chg->jeita_cool_fcc_ua); + if (rc < 0) + chg->jeita_cool_fcc_ua = -EINVAL; + } + + if (chg->jeita_use_aux) { + /* JEITA AUX_THERM threshold*/ + rc = of_property_read_u32(node, "somc,jeita-aux-thresh-hot", + &chg->jeita_aux_thresh_hot); + if (rc < 0) { + pr_err("Coudn't find jeita-aux-thresh-hot\n"); + chg->jeita_use_aux = false; + } + + rc = of_property_read_u32(node, "somc,jeita-aux-thresh-warm", + &chg->jeita_aux_thresh_warm); + if (rc < 0) { + pr_err("Coudn't find jeita-aux-thresh-warm\n"); + chg->jeita_use_aux = false; + } + + if (chg->jeita_aux_thresh_hot <= + chg->jeita_aux_thresh_warm) { + pr_err("Invalid parameter jeita_aux_thresh_warm/hot\n"); + chg->jeita_use_aux = false; + } + } + + if (chg->jeita_sw_ctl_en) + pr_debug("JEITA SW Contorol is enabled.\n"); + else + pr_debug("JEITA SW Contorol is disabled.\n"); + + if (chg->jeita_use_aux) + pr_debug("AUX_THERM Monitoring is enabled.\n"); + else + pr_debug("AUX_THERM Monitoring is disabled.\n"); + +#endif return 0; } @@ -351,6 +590,9 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_PD_VOLTAGE_MAX, POWER_SUPPLY_PROP_PD_VOLTAGE_MIN, POWER_SUPPLY_PROP_SDP_CURRENT_MAX, +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + POWER_SUPPLY_PROP_CHARGER_TYPE, +#endif }; static int smb2_usb_get_prop(struct power_supply *psy, @@ -379,8 +621,10 @@ static int smb2_usb_get_prop(struct power_supply *psy, val->intval = 0; else val->intval = 1; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN) val->intval = 0; +#endif break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_get_prop_usb_voltage_max(chg, val); @@ -466,6 +710,11 @@ static int smb2_usb_get_prop(struct power_supply *psy, val->intval = get_client_vote(chg->usb_icl_votable, USB_PSY_VOTER); break; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + case POWER_SUPPLY_PROP_CHARGER_TYPE: + val->strval = smblib_somc_get_charger_type(chg); + break; +#endif default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -487,7 +736,9 @@ static int smb2_usb_set_prop(struct power_supply *psy, int rc = 0; mutex_lock(&chg->lock); - if (!chg->typec_present) { + if (!chg->typec_present && + psp != POWER_SUPPLY_PROP_TYPEC_POWER_ROLE) { + pr_warn("set_prop is inhibited because typec is not present\n"); rc = -EINVAL; goto unlock; } @@ -563,6 +814,9 @@ static int smb2_init_usb_psy(struct smb2 *chip) chg->usb_psy_desc.get_property = smb2_usb_get_prop; chg->usb_psy_desc.set_property = smb2_usb_set_prop; chg->usb_psy_desc.property_is_writeable = smb2_usb_prop_is_writeable; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chg->usb_params.apsd_result_bit = 0; +#endif usb_cfg.drv_data = chip; usb_cfg.of_node = chg->dev->of_node; @@ -612,7 +866,7 @@ static int smb2_usb_port_get_prop(struct power_supply *psy, val->intval = 0; break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: - val->intval = 5000000; + rc = smblib_get_prop_usb_voltage_max(chg, val); break; case POWER_SUPPLY_PROP_CURRENT_MAX: rc = smblib_get_prop_input_current_settled(chg, val); @@ -798,7 +1052,6 @@ static enum power_supply_property smb2_dc_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CURRENT_MAX, - POWER_SUPPLY_PROP_REAL_TYPE, }; static int smb2_dc_get_prop(struct power_supply *psy, @@ -819,9 +1072,6 @@ static int smb2_dc_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_MAX: rc = smblib_get_prop_dc_current_max(chg, val); break; - case POWER_SUPPLY_PROP_REAL_TYPE: - val->intval = POWER_SUPPLY_TYPE_WIPOWER; - break; default: return -EINVAL; } @@ -870,7 +1120,7 @@ static int smb2_dc_prop_is_writeable(struct power_supply *psy, static const struct power_supply_desc dc_psy_desc = { .name = "dc", - .type = POWER_SUPPLY_TYPE_WIRELESS, + .type = POWER_SUPPLY_TYPE_WIPOWER, .properties = smb2_dc_props, .num_properties = ARRAY_SIZE(smb2_dc_props), .get_property = smb2_dc_get_prop, @@ -901,6 +1151,10 @@ static int smb2_init_dc_psy(struct smb2 *chip) *************************/ static enum power_supply_property smb2_batt_props[] = { +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_SKIN_TEMP, +#endif POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_HEALTH, @@ -920,7 +1174,7 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, - POWER_SUPPLY_PROP_SW_JEITA_ENABLED, + POWER_SUPPLY_PROP_STEP_CHARGING_STEP, POWER_SUPPLY_PROP_CHARGE_DONE, POWER_SUPPLY_PROP_PARALLEL_DISABLE, POWER_SUPPLY_PROP_SET_SHIP_MODE, @@ -928,6 +1182,19 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_RERUN_AICL, POWER_SUPPLY_PROP_DP_DM, POWER_SUPPLY_PROP_CHARGE_COUNTER, +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + POWER_SUPPLY_PROP_SMART_CHARGING_ACTIVATION, + POWER_SUPPLY_PROP_SMART_CHARGING_INTERRUPTION, + POWER_SUPPLY_PROP_SMART_CHARGING_STATUS, + POWER_SUPPLY_PROP_LRC_ENABLE, + POWER_SUPPLY_PROP_LRC_SOCMAX, + POWER_SUPPLY_PROP_LRC_SOCMIN, + POWER_SUPPLY_PROP_LRC_NOT_STARTUP, + POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_INT_CLD, +#endif }; static int smb2_batt_get_prop(struct power_supply *psy, @@ -948,6 +1215,11 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_PRESENT: rc = smblib_get_prop_batt_present(chg, val); break; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + rc = smblib_get_prop_charging_enabled(chg, val); + break; +#endif case POWER_SUPPLY_PROP_INPUT_SUSPEND: rc = smblib_get_prop_input_suspend(chg, val); break; @@ -960,6 +1232,11 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: rc = smblib_get_prop_system_temp_level(chg, val); break; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + case POWER_SUPPLY_PROP_SKIN_TEMP: + rc = smblib_get_prop_skin_temp(chg, val); + break; +#endif case POWER_SUPPLY_PROP_CHARGER_TEMP: /* do not query RRADC if charger is not present */ rc = smblib_get_prop_usb_present(chg, &pval); @@ -979,8 +1256,8 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: val->intval = chg->step_chg_enabled; break; - case POWER_SUPPLY_PROP_SW_JEITA_ENABLED: - val->intval = chg->sw_jeita_enabled; + case POWER_SUPPLY_PROP_STEP_CHARGING_STEP: + rc = smblib_get_prop_step_chg_step(chg, val); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: rc = smblib_get_prop_batt_voltage_now(chg, val); @@ -1036,6 +1313,39 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER: rc = smblib_get_prop_batt_charge_counter(chg, val); break; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + case POWER_SUPPLY_PROP_SMART_CHARGING_ACTIVATION: + val->intval = chg->smart_charge_enabled; + break; + case POWER_SUPPLY_PROP_SMART_CHARGING_INTERRUPTION: + case POWER_SUPPLY_PROP_SMART_CHARGING_STATUS: + val->intval = chg->smart_charge_suspended; + break; + case POWER_SUPPLY_PROP_LRC_ENABLE: + val->intval = chg->lrc_enabled; + break; + case POWER_SUPPLY_PROP_LRC_SOCMAX: + val->intval = chg->lrc_socmax; + break; + case POWER_SUPPLY_PROP_LRC_SOCMIN: + val->intval = chg->lrc_socmin; + break; + case POWER_SUPPLY_PROP_LRC_NOT_STARTUP: + val->intval = chg->lrc_fake_capacity; + break; + case POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT: + val->intval = get_client_vote(chg->fcc_votable, QNS_VOTER); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + rc = smblib_get_prop_charge_full_design(chg, val); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + rc = smblib_get_prop_charge_full(chg, val); + break; + case POWER_SUPPLY_PROP_INT_CLD: + val->intval = chg->int_cld; + break; +#endif default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; @@ -1049,6 +1359,10 @@ static int smb2_batt_get_prop(struct power_supply *psy, return 0; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define FAKE_CAPACITY_HYSTERISIS 1 + +#endif static int smb2_batt_set_prop(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) @@ -1057,6 +1371,11 @@ static int smb2_batt_set_prop(struct power_supply *psy, struct smb_charger *chg = power_supply_get_drvdata(psy); switch (prop) { +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + rc = smblib_set_prop_charging_enabled(chg, val); + break; +#endif case POWER_SUPPLY_PROP_INPUT_SUSPEND: rc = smblib_set_prop_input_suspend(chg, val); break; @@ -1098,16 +1417,6 @@ static int smb2_batt_set_prop(struct power_supply *psy, vote(chg->fcc_votable, BATT_PROFILE_VOTER, false, 0); } break; - case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: - chg->step_chg_enabled = !!val->intval; - break; - case POWER_SUPPLY_PROP_SW_JEITA_ENABLED: - if (chg->sw_jeita_enabled != (!!val->intval)) { - rc = smblib_disable_hw_jeita(chg, !!val->intval); - if (rc == 0) - chg->sw_jeita_enabled = !!val->intval; - } - break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: chg->batt_profile_fcc_ua = val->intval; vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval); @@ -1130,6 +1439,44 @@ static int smb2_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: rc = smblib_set_prop_input_current_limited(chg, val); break; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + case POWER_SUPPLY_PROP_SMART_CHARGING_ACTIVATION: + if (val->intval) { + pr_debug("Smart Charging was activated.\n"); + chg->smart_charge_enabled = true; + } + break; + case POWER_SUPPLY_PROP_SMART_CHARGING_INTERRUPTION: + if (chg->smart_charge_enabled) { + chg->smart_charge_suspended = (bool)val->intval; + rc = smblib_somc_smart_set_suspend(chg); + power_supply_changed(chg->batt_psy); + } + break; + case POWER_SUPPLY_PROP_LRC_ENABLE: + chg->lrc_enabled = val->intval; + smblib_somc_lrc_check(chg); + break; + case POWER_SUPPLY_PROP_LRC_SOCMAX: + chg->lrc_socmax = (int)val->intval; + break; + case POWER_SUPPLY_PROP_LRC_SOCMIN: + chg->lrc_socmin = (int)val->intval; + break; + case POWER_SUPPLY_PROP_LRC_NOT_STARTUP: + chg->lrc_fake_capacity = (int)val->intval; + if (chg->lrc_fake_capacity) + chg->lrc_hysterisis = FAKE_CAPACITY_HYSTERISIS; + break; + case POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT: + vote(chg->fcc_votable, QNS_VOTER, true, val->intval); + break; + case POWER_SUPPLY_PROP_INT_CLD: + chg->int_cld = (int)val->intval; + if (chg->int_cld) + power_supply_changed(chg->batt_psy); + break; +#endif default: rc = -EINVAL; } @@ -1141,6 +1488,9 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy, enum power_supply_property psp) { switch (psp) { +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + case POWER_SUPPLY_PROP_CHARGING_ENABLED: +#endif case POWER_SUPPLY_PROP_INPUT_SUSPEND: case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: case POWER_SUPPLY_PROP_CAPACITY: @@ -1148,8 +1498,16 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_DP_DM: case POWER_SUPPLY_PROP_RERUN_AICL: case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: - case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: - case POWER_SUPPLY_PROP_SW_JEITA_ENABLED: +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + case POWER_SUPPLY_PROP_SMART_CHARGING_ACTIVATION: + case POWER_SUPPLY_PROP_SMART_CHARGING_INTERRUPTION: + case POWER_SUPPLY_PROP_LRC_ENABLE: + case POWER_SUPPLY_PROP_LRC_SOCMAX: + case POWER_SUPPLY_PROP_LRC_SOCMIN: + case POWER_SUPPLY_PROP_LRC_NOT_STARTUP: + case POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_INT_CLD: +#endif return 1; default: break; @@ -1195,6 +1553,10 @@ struct regulator_ops smb2_vbus_reg_ops = { .enable = smblib_vbus_regulator_enable, .disable = smblib_vbus_regulator_disable, .is_enabled = smblib_vbus_regulator_is_enabled, +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + .register_ocp_notification + = somc_usb_otg_regulator_register_ocp_notification, +#endif }; static int smb2_init_vbus_regulator(struct smb2 *chip) @@ -1277,6 +1639,73 @@ static int smb2_init_vconn_regulator(struct smb2 *chip) /*************************** * HARDWARE INITIALIZATION * ***************************/ +static int smb2_config_step_charging(struct smb2 *chip) +{ + struct smb_charger *chg = &chip->chg; + int rc = 0; + int i; + + if (!chg->step_chg_enabled) + return rc; + + for (i = 0; i < STEP_CHARGING_MAX_STEPS - 1; i++) { + rc = smblib_set_charge_param(chg, + &chg->param.step_soc_threshold[i], + chip->dt.step_soc_threshold[i]); + if (rc < 0) { + pr_err("Couldn't configure soc thresholds rc = %d\n", + rc); + goto err_out; + } + } + + for (i = 0; i < STEP_CHARGING_MAX_STEPS; i++) { + rc = smblib_set_charge_param(chg, &chg->param.step_cc_delta[i], + chip->dt.step_cc_delta[i]); + if (rc < 0) { + pr_err("Couldn't configure cc delta rc = %d\n", + rc); + goto err_out; + } + } + + rc = smblib_write(chg, STEP_CHG_UPDATE_REQUEST_TIMEOUT_CFG_REG, + STEP_CHG_UPDATE_REQUEST_TIMEOUT_40S); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure soc request timeout reg rc=%d\n", + rc); + goto err_out; + } + + rc = smblib_write(chg, STEP_CHG_UPDATE_FAIL_TIMEOUT_CFG_REG, + STEP_CHG_UPDATE_FAIL_TIMEOUT_120S); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure soc fail timeout reg rc=%d\n", + rc); + goto err_out; + } + + /* + * enable step charging, source soc, standard mode, go to final + * state in case of failure. + */ + rc = smblib_write(chg, CHGR_STEP_CHG_MODE_CFG_REG, + STEP_CHARGING_ENABLE_BIT | + STEP_CHARGING_SOURCE_SELECT_BIT | + STEP_CHARGING_SOC_FAIL_OPTION_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure charger rc=%d\n", rc); + goto err_out; + } + + return 0; +err_out: + chg->step_chg_enabled = false; + return rc; +} + static int smb2_config_wipower_input_power(struct smb2 *chip, int uw) { int rc; @@ -1452,7 +1881,7 @@ static int smb2_init_hw(struct smb2 *chip) { struct smb_charger *chg = &chip->chg; int rc; - u8 stat, val; + u8 stat; if (chip->dt.no_battery) chg->fake_capacity = 50; @@ -1501,6 +1930,14 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chg->product_icl_ua < 0) + chg->product_icl_ua = chg->default_icl_ua; + + if (chg->high_voltage_icl_ua < 0) + chg->high_voltage_icl_ua = chg->default_icl_ua; +#endif + chg->boost_threshold_ua = chip->dt.boost_threshold_ua; rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat); @@ -1518,6 +1955,10 @@ static int smb2_init_hw(struct smb2 *chip) } /* votes must be cast before configuring software control */ +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 0); + vote(chg->usb_icl_votable, PRODUCT_VOTER, true, chg->product_icl_ua); +#endif /* vote 0mA on usb_icl for non battery platforms */ vote(chg->usb_icl_votable, DEFAULT_VOTER, chip->dt.no_battery, 0); @@ -1543,7 +1984,16 @@ static int smb2_init_hw(struct smb2 *chip) chg->micro_usb_mode, 0); vote(chg->hvdcp_enable_votable, MICRO_USB_VOTER, chg->micro_usb_mode, 0); - +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* ICL is controlled by SW always */ + rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG, + AICL_USE_SW_AFTER_APSD, AICL_USE_SW_AFTER_APSD); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't set AICL_USE_SW_AFTER_APSD rc=%d\n", rc); + return rc; + } +#endif /* * AICL configuration: * start from min and AICL ADC disable @@ -1555,7 +2005,127 @@ static int smb2_init_hw(struct smb2 *chip) dev_err(chg->dev, "Couldn't configure AICL rc=%d\n", rc); return rc; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* Vote thermal fcc at Lv0 */ + smblib_somc_thermal_icl_change(chg); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* disable watchdog timer */ + rc = smblib_write(chg, WD_CFG_REG, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't wdog cfg rc=%d\n", rc); + return rc; + } + + /* just in case, allow charging when bite watchdog timer expires */ + rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG, + BITE_WDOG_DISABLE_CHARGING_CFG_BIT, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't enable wdog charging rc=%d\n", rc); + return rc; + } + + /* set adapter allowance to default value */ + rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, + USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V); + if (rc < 0) { + dev_err(chg->dev, "Couldn't set adapter allow cfg rc=%d\n", rc); + return rc; + } + + /* add a setting to prevent the rise of output voltage over 9V */ + rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_CFG_REG, + HVDCP_PULSE_COUNT_MAX_QC3P0 | + HVDCP_PULSE_COUNT_MAX_QC2P0, + QC3P0_MAX_PULSE_9V | QC2P0_MAX_PULSE_9V); + if (rc < 0) { + dev_err(chg->dev, "Couldn't set hvdcp pulse cfg rc=%d\n", rc); + return rc; + } + + /* Disable INOV controller */ + rc = smblib_masked_write(chg, THERMREG_SRC_CFG_REG, + THERMREG_SKIN_ADC_SRC_EN_BIT | + THERMREG_DIE_ADC_SRC_EN_BIT | + THERMREG_DIE_CMP_SRC_EN_BIT, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable INOV rc=%d\n", rc); + return rc; + } + + rc = smblib_masked_write(chg, USBIN_5V_AICL_THRESHOLD_CFG_REG, + USBIN_5V_AICL_THRESHOLD_CFG_MASK, + USBIN_5V_AICL_THRESHOLD_4P5V); + if (rc < 0) { + dev_err(chg->dev, "Couldn't set 5v aicl thresh rc=%d\n", rc); + return rc; + } + + rc = smblib_masked_write(chg, USBIN_9V_AICL_THRESHOLD_CFG_REG, + USBIN_9V_AICL_THRESHOLD_CFG_MASK, + USBIN_9V_AICL_THRESHOLD_7P6V); + if (rc < 0) { + dev_err(chg->dev, "Couldn't set 9v aicl thresh rc=%d\n", rc); + return rc; + } + + rc = smblib_masked_write(chg, USBIN_CONT_AICL_THRESHOLD_CFG_REG, + USBIN_CONT_AICL_THRESHOLD_CFG_MASK, + USBIN_CONT_AICL_THRESHOLD_4P5V); + if (rc < 0) { + dev_err(chg->dev, "Couldn't set cont aicl thresh rc=%d\n", rc); + return rc; + } + + rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG, + USBIN_IN_COLLAPSE_GF_SEL, + USBIN_IN_COLLAPSE_GF_30US); + if (rc < 0) { + dev_err(chg->dev, "Couldn't set Glitch Filter rc=%d\n", rc); + return rc; + } + + /* Enable JEITA Hard Limit under any settings */ + rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, + JEITA_EN_HARDLIMIT_BIT, + JEITA_EN_HARDLIMIT_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't enable JEITA Hard Limit rc=%d\n", + rc); + return rc; + } + + if (chg->jeita_sw_ctl_en) { + /* Disable FVCOMP and CCCOMP with warm and cool */ + rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, + JEITA_EN_HOT_SL_FCV_BIT | + JEITA_EN_COLD_SL_FCV_BIT | + JEITA_EN_HOT_SL_CCC_BIT | + JEITA_EN_COLD_SL_CCC_BIT, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable JEITA comp rc=%d\n", + rc); + return rc; + } + + /* Disable FVCOMP CFG */ + rc = smblib_write(chg, JEITA_FVCOMP_CFG_REG, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable fvcomp cfg rc=%d\n", + rc); + return rc; + } + + /* Disable CCCOMP CFG */ + rc = smblib_write(chg, JEITA_CCCOMP_CFG_REG, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable cc comp rc=%d\n", + rc); + return rc; + } + } +#endif /* Configure charge enable for software control; active high */ rc = smblib_masked_write(chg, CHGR_CFG2_REG, CHG_EN_POLARITY_BIT | @@ -1600,27 +2170,11 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } - val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT) & - BARK_WDOG_TIMEOUT_MASK; - val |= BITE_WDOG_TIMEOUT_8S; - rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG, - BITE_WDOG_DISABLE_CHARGING_CFG_BIT | - BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK, - val); - if (rc) { - pr_err("Couldn't configue WD config rc=%d\n", rc); - return rc; - } - - /* enable WD BARK and enable it on plugin */ - rc = smblib_masked_write(chg, WD_CFG_REG, - WATCHDOG_TRIGGER_AFP_EN_BIT | - WDOG_TIMER_EN_ON_PLUGIN_BIT | - BARK_WDOG_INT_EN_BIT, - WDOG_TIMER_EN_ON_PLUGIN_BIT | - BARK_WDOG_INT_EN_BIT); - if (rc) { - pr_err("Couldn't configue WD config rc=%d\n", rc); + /* configure step charging */ + rc = smb2_config_step_charging(chip); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure step charging rc=%d\n", + rc); return rc; } @@ -1679,13 +2233,6 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } - rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg); - if (rc < 0) { - dev_err(chg->dev, "Couldn't read float charger options rc=%d\n", - rc); - return rc; - } - switch (chip->dt.chg_inhibit_thr_mv) { case 50: rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG, @@ -1742,14 +2289,6 @@ static int smb2_init_hw(struct smb2 *chip) } } - if (chg->sw_jeita_enabled) { - rc = smblib_disable_hw_jeita(chg, true); - if (rc < 0) { - dev_err(chg->dev, "Couldn't set hw jeita rc=%d\n", rc); - return rc; - } - } - return rc; } @@ -1758,12 +2297,6 @@ static int smb2_post_init(struct smb2 *chip) struct smb_charger *chg = &chip->chg; int rc; - /* In case the usb path is suspended, we would have missed disabling - * the icl change interrupt because the interrupt could have been - * not requested - */ - rerun_election(chg->usb_icl_votable); - /* configure power role for dual-role */ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, TYPEC_POWER_ROLE_CMD_MASK, 0); @@ -1822,8 +2355,8 @@ static int smb2_chg_config_init(struct smb2 *chip) chip->chg.wa_flags |= BOOST_BACK_WA | OTG_WA; chg->param.freq_buck = pm660_params.freq_buck; chg->param.freq_boost = pm660_params.freq_boost; - chg->chg_freq.freq_5V = 650; - chg->chg_freq.freq_6V_8V = 850; + chg->chg_freq.freq_5V = 600; + chg->chg_freq.freq_6V_8V = 800; chg->chg_freq.freq_9V = 1050; chg->chg_freq.freq_12V = 1200; chg->chg_freq.freq_removal = 1050; @@ -1855,8 +2388,8 @@ static int smb2_determine_initial_status(struct smb2 *chip) smblib_handle_usb_source_change(0, &irq_data); smblib_handle_chg_state_change(0, &irq_data); smblib_handle_icl_change(0, &irq_data); - smblib_handle_batt_temp_changed(0, &irq_data); - smblib_handle_wdog_bark(0, &irq_data); + smblib_handle_step_chg_state_change(0, &irq_data); + smblib_handle_step_chg_soc_update_request(0, &irq_data); return 0; } @@ -1878,15 +2411,18 @@ static struct smb_irq_info smb2_irqs[] = { }, [STEP_CHG_STATE_CHANGE_IRQ] = { .name = "step-chg-state-change", - .handler = NULL, + .handler = smblib_handle_step_chg_state_change, + .wake = true, }, [STEP_CHG_SOC_UPDATE_FAIL_IRQ] = { .name = "step-chg-soc-update-fail", - .handler = NULL, + .handler = smblib_handle_step_chg_soc_update_fail, + .wake = true, }, [STEP_CHG_SOC_UPDATE_REQ_IRQ] = { .name = "step-chg-soc-update-request", - .handler = NULL, + .handler = smblib_handle_step_chg_soc_update_request, + .wake = true, }, /* OTG IRQs */ [OTG_FAIL_IRQ] = { @@ -1909,7 +2445,6 @@ static struct smb_irq_info smb2_irqs[] = { [BATT_TEMP_IRQ] = { .name = "bat-temp", .handler = smblib_handle_batt_temp_changed, - .wake = true, }, [BATT_OCP_IRQ] = { .name = "bat-ocp", @@ -2005,8 +2540,7 @@ static struct smb_irq_info smb2_irqs[] = { }, [WDOG_BARK_IRQ] = { .name = "wdog-bark", - .handler = smblib_handle_wdog_bark, - .wake = true, + .handler = NULL, }, [AICL_FAIL_IRQ] = { .name = "aicl-fail", @@ -2014,7 +2548,12 @@ static struct smb_irq_info smb2_irqs[] = { }, [AICL_DONE_IRQ] = { .name = "aicl-done", +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) .handler = smblib_handle_debug, +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + .handler = smblib_handle_aicl_done, +#endif }, [HIGH_DUTY_CYCLE_IRQ] = { .name = "high-duty-cycle", @@ -2112,8 +2651,6 @@ static int smb2_request_interrupts(struct smb2 *chip) return rc; } } - if (chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq) - chg->usb_icl_change_irq_enabled = true; return rc; } @@ -2212,6 +2749,543 @@ static void smb2_create_debugfs(struct smb2 *chip) #endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +/***************************** + * somc sysfs implementation * + *****************************/ +enum smb2_somc_sysfs { + ATTR_CHGR_BATTERY_CHARGER_STATUS_1 = 0, + ATTR_CHGR_BATTERY_CHARGER_STATUS_2, + ATTR_CHGR_BATTERY_CHARGER_STATUS_3, + ATTR_CHGR_BATTERY_CHARGER_STATUS_4, + ATTR_CHGR_BATTERY_CHARGER_STATUS_5, + ATTR_CHGR_BATTERY_CHARGER_STATUS_6, + ATTR_CHGR_BATTERY_CHARGER_STATUS_7, + ATTR_CHGR_BATTERY_CHARGER_STATUS_8, + ATTR_CHGR_INT_RT_STS, + ATTR_CHGR_FAST_CHARGE_CURRENT_CFG, + ATTR_CHGR_FLOAT_VOLTAGE_CFG, + ATTR_BATIF_INT_RT_STS, + ATTR_USB_USBIN_INPUT_STATUS, + ATTR_USB_APSD_STATUS, + ATTR_USB_APSD_RESULT_STATUS, + ATTR_USB_QC_CHANGE_STATUS, + ATTR_USB_QC_PULSE_COUNT_STATUS, + ATTR_USB_TYPE_C_STATUS_1, + ATTR_USB_TYPE_C_STATUS_2, + ATTR_USB_TYPE_C_STATUS_3, + ATTR_USB_TYPE_C_STATUS_4, + ATTR_USB_TYPE_C_STATUS_5, + ATTR_USB_INT_RT_STS, + ATTR_USB_CMD_IL, + ATTR_USB_USBIN_CURRENT_LIMIT_CFG, + ATTR_MISC_TEMP_RANGE_STATUS, + ATTR_MISC_ICL_STATUS, + ATTR_MISC_ADAPTER_5V_ICL_STATUS, + ATTR_MISC_ADAPTER_9V_ICL_STATUS, + ATTR_MISC_AICL_STATUS, + ATTR_MISC_POWER_PATH_STATUS, + ATTR_MISC_WDOG_STATUS, + ATTR_MISC_INT_RT_STS, + ATTR_USB_ICL_VOTER, + ATTR_USB_ICL_VOTER_EFFECTIVE, + ATTR_FCC_VOTER, + ATTR_FCC_VOTER_EFFECTIVE, + ATTR_CHG_DISABLE_VOTER, + ATTR_ENABLE_SHUTDOWN_AT_LOW_BATTERY, + ATTR_USB_MAX_CURRENT_HC, + ATTR_USB_MAX_CURRENT_LIMITED, + ATTR_FV_VOTER, + ATTR_FV_VOTER_EFFECTIVE, + ATTR_JEITA_AUX_THRESH_HOT, + ATTR_JEITA_AUX_THRESH_WARM, + ATTR_USBIN_ADAPTER_ALLOW_CFG, + ATTR_FAKED_STATUS, +}; + +static ssize_t smb2_somc_param_show(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t smb2_somc_param_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +static struct device_attribute smb2_somc_attrs[] = { + __ATTR(bat_chg_sts1, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(bat_chg_sts2, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(bat_chg_sts3, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(bat_chg_sts4, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(bat_chg_sts5, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(bat_chg_sts6, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(bat_chg_sts7, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(bat_chg_sts8, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(chgr_int_rt_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(fast_chg_current_cfg, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(float_voltage_cfg, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(batif_int_rt_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(usbin_input_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(apsd_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(apsd_result_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(qc_change_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(qc_pulse_count_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(type_c_sts1, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(type_c_sts2, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(type_c_sts3, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(type_c_sts4, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(type_c_sts5, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(usb_int_rt_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(cmd_il, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(usbin_current_limit_cfg, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(temp_renge_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(icl_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(adapter_5v_icl_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(adapter_9v_icl_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(aicl_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(power_path_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(wdog_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(misc_int_rt_sts, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(usb_icl_voter, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(usb_icl_voter_effective, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(fcc_voter, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(fcc_voter_effective, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(chg_disable_voter, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(enable_shutdown_at_low_battery, S_IRUGO|S_IWUSR, + smb2_somc_param_show, smb2_somc_param_store), + __ATTR(usb_max_current_hc, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(usb_max_current_limited, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(fv_voter, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(fv_voter_effective, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(jeita_aux_thresh_hot, S_IRUGO|S_IWUSR, + smb2_somc_param_show, smb2_somc_param_store), + __ATTR(jeita_aux_thresh_warm, S_IRUGO|S_IWUSR, + smb2_somc_param_show, smb2_somc_param_store), + __ATTR(usbin_adapter_allow_cfg, S_IRUGO, smb2_somc_param_show, NULL), + __ATTR(faked_status, S_IRUGO, smb2_somc_param_show, NULL), +}; + +static ssize_t smb2_somc_param_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct smb2 *chip = dev_get_drvdata(dev); + struct smb_charger *chg = &chip->chg; + ssize_t size = 0; + const ptrdiff_t off = attr - smb2_somc_attrs; + int ret = 0; + u8 reg; + + switch (off) { + case ATTR_CHGR_BATTERY_CHARGER_STATUS_1: + ret = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, ®); + if (ret) + dev_err(dev, + "Can't read BATTERY_CHARGER_STATUS_1: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_BATTERY_CHARGER_STATUS_2: + ret = smblib_read(chg, + BATTERY_CHARGER_STATUS_2_REG, ®); + if (ret) + dev_err(dev, + "Can't read BATTERY_CHARGER_STATUS_2: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_BATTERY_CHARGER_STATUS_3: + ret = smblib_read(chg, BATTERY_CHARGER_STATUS_3_REG, ®); + if (ret) + dev_err(dev, + "Can't read BATTERY_CHARGER_STATUS_3: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_BATTERY_CHARGER_STATUS_4: + ret = smblib_read(chg, BATTERY_CHARGER_STATUS_4_REG, ®); + if (ret) + dev_err(dev, + "Can't read BATTERY_CHARGER_STATUS_4: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_BATTERY_CHARGER_STATUS_5: + ret = smblib_read(chg, BATTERY_CHARGER_STATUS_5_REG, ®); + if (ret) + dev_err(dev, + "Can't read BATTERY_CHARGER_STATUS_5: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_BATTERY_CHARGER_STATUS_6: + ret = smblib_read(chg, BATTERY_CHARGER_STATUS_6_REG, ®); + if (ret) + dev_err(dev, + "Can't read BATTERY_CHARGER_STATUS_6: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_BATTERY_CHARGER_STATUS_7: + ret = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, ®); + if (ret) + dev_err(dev, + "Can't read BATTERY_CHARGER_STATUS_7: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_BATTERY_CHARGER_STATUS_8: + ret = smblib_read(chg, BATTERY_CHARGER_STATUS_8_REG, ®); + if (ret) + dev_err(dev, + "Can't read BATTERY_CHARGER_STATUS_8: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_INT_RT_STS: + ret = smblib_read(chg, CHGR_INT_RT_STS_REG, ®); + if (ret) + dev_err(dev, + "Can't read CHGR_INT_RT_STS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_FAST_CHARGE_CURRENT_CFG: + ret = smblib_read(chg, FAST_CHARGE_CURRENT_CFG_REG, ®); + if (ret) + dev_err(dev, + "Can't read FAST_CHARGE_CURRENT_CFG: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_CHGR_FLOAT_VOLTAGE_CFG: + ret = smblib_read(chg, FLOAT_VOLTAGE_CFG_REG, ®); + if (ret) + dev_err(dev, + "Can't read FLOAT_VOLTAGE_CFG: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_BATIF_INT_RT_STS: + ret = smblib_read(chg, BATIF_INT_RT_STS_REG, ®); + if (ret) + dev_err(dev, + "Can't read BATIF_INT_RT_STS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_USBIN_INPUT_STATUS: + ret = smblib_read(chg, USBIN_INPUT_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read USBIN_INPUT_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_APSD_STATUS: + ret = smblib_read(chg, APSD_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read APSD_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_APSD_RESULT_STATUS: + ret = smblib_read(chg, APSD_RESULT_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read APSD_RESULT_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_QC_CHANGE_STATUS: + ret = smblib_read(chg, QC_CHANGE_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read QC_CHANGE_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_QC_PULSE_COUNT_STATUS: + ret = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read QC_PULSE_COUNT_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_TYPE_C_STATUS_1: + ret = smblib_read(chg, TYPE_C_STATUS_1_REG, ®); + if (ret) + dev_err(dev, + "Can't read TYPE_C_STATUS_1: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_TYPE_C_STATUS_2: + ret = smblib_read(chg, TYPE_C_STATUS_2_REG, ®); + if (ret) + dev_err(dev, + "Can't read TYPE_C_STATUS_2: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_TYPE_C_STATUS_3: + ret = smblib_read(chg, TYPE_C_STATUS_3_REG, ®); + if (ret) + dev_err(dev, + "Can't read TYPE_C_STATUS_3: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_TYPE_C_STATUS_4: + ret = smblib_read(chg, TYPE_C_STATUS_4_REG, ®); + if (ret) + dev_err(dev, + "Can't read TYPE_C_STATUS_4: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_TYPE_C_STATUS_5: + ret = smblib_read(chg, TYPE_C_STATUS_5_REG, ®); + if (ret) + dev_err(dev, + "Can't read TYPE_C_STATUS_5: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_INT_RT_STS: + ret = smblib_read(chg, USB_INT_RT_STS_REG, ®); + if (ret) + dev_err(dev, + "Can't read USB_INT_RT_STS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_CMD_IL: + ret = smblib_read(chg, USBIN_CMD_IL_REG, ®); + if (ret) + dev_err(dev, + "Can't read USBIN_CMD_IL: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_USBIN_CURRENT_LIMIT_CFG: + ret = smblib_read(chg, USBIN_CURRENT_LIMIT_CFG_REG, ®); + if (ret) + dev_err(dev, + "Can't read USBIN_CURRENT_LIMIT_CFG: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_MISC_TEMP_RANGE_STATUS: + ret = smblib_read(chg, TEMP_RANGE_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read TEMP_RANGE_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_MISC_ICL_STATUS: + ret = smblib_read(chg, ICL_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read MISC_ICL_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_MISC_ADAPTER_5V_ICL_STATUS: + ret = smblib_read(chg, ADAPTER_5V_ICL_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read ADAPTER_5V_ICL_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_MISC_ADAPTER_9V_ICL_STATUS: + ret = smblib_read(chg, ADAPTER_9V_ICL_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read ADAPTER_9V_ICL_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_MISC_AICL_STATUS: + ret = smblib_read(chg, AICL_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read MISC_AICL_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_MISC_POWER_PATH_STATUS: + ret = smblib_read(chg, POWER_PATH_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read POWER_PATH_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_MISC_WDOG_STATUS: + ret = smblib_read(chg, WDOG_STATUS_REG, ®); + if (ret) + dev_err(dev, + "Can't read WDOG_STATUS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_MISC_INT_RT_STS: + ret = smblib_read(chg, MISC_INT_RT_STS_REG, ®); + if (ret) + dev_err(dev, + "Can't read MISC_INT_RT_STS: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_USB_ICL_VOTER: + size = somc_output_voter_param(chg->usb_icl_votable, + buf, PAGE_SIZE); + break; + case ATTR_USB_ICL_VOTER_EFFECTIVE: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + get_effective_result(chg->usb_icl_votable)); + break; + case ATTR_FCC_VOTER: + size = somc_output_voter_param(chg->fcc_votable, + buf, PAGE_SIZE); + break; + case ATTR_FCC_VOTER_EFFECTIVE: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + get_effective_result(chg->fcc_votable)); + break; + case ATTR_CHG_DISABLE_VOTER: + size = somc_output_voter_param(chg->chg_disable_votable, + buf, PAGE_SIZE); + break; + case ATTR_ENABLE_SHUTDOWN_AT_LOW_BATTERY: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + chg->low_batt_shutdown_enabled); + break; + case ATTR_USB_MAX_CURRENT_HC: + ret = smblib_read(chg, USBIN_CURRENT_LIMIT_CFG_REG, ®); + if (ret) + dev_err(dev, + "Can't read USBIN_CURRENT_LIMIT_CFG: %d\n", ret); + else + size = scnprintf(buf, PAGE_SIZE, "%d\n", reg * 25); + break; + case ATTR_USB_MAX_CURRENT_LIMITED: + ret = smblib_get_usb_max_current_limited(chg); + if (ret) + size = scnprintf(buf, PAGE_SIZE, "%d\n", ret); + break; + case ATTR_FV_VOTER: + size = somc_output_voter_param(chg->fv_votable, buf, PAGE_SIZE); + break; + case ATTR_FV_VOTER_EFFECTIVE: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + get_effective_result(chg->fv_votable)); + break; + case ATTR_JEITA_AUX_THRESH_HOT: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + chg->jeita_aux_thresh_hot); + break; + case ATTR_JEITA_AUX_THRESH_WARM: + size = scnprintf(buf, PAGE_SIZE, "%d\n", + chg->jeita_aux_thresh_warm); + break; + case ATTR_USBIN_ADAPTER_ALLOW_CFG: + ret = smblib_read(chg, USBIN_ADAPTER_ALLOW_CFG_REG, ®); + if (ret) + dev_err(dev, + "Can't read USBIN_ADAPTER_ALLOW_CFG_REG: %d\n", + ret); + else + size = scnprintf(buf, PAGE_SIZE, "0x%02X\n", reg); + break; + case ATTR_FAKED_STATUS: + size = scnprintf(buf, PAGE_SIZE, "%d\n", chg->faked_status); + break; + default: + size = 0; + break; + } + return size; +} + +static ssize_t smb2_somc_param_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct smb2 *chip = dev_get_drvdata(dev); + struct smb_charger *chg = &chip->chg; + const ptrdiff_t off = attr - smb2_somc_attrs; + int ret; + + switch (off) { + case ATTR_ENABLE_SHUTDOWN_AT_LOW_BATTERY: + ret = kstrtoint(buf, 10, &chg->low_batt_shutdown_enabled); + if (ret < 0) { + count = 0; + break; + } + break; + case ATTR_JEITA_AUX_THRESH_HOT: + ret = kstrtoint(buf, 10, &chg->jeita_aux_thresh_hot); + if (ret < 0) { + count = 0; + break; + } + break; + case ATTR_JEITA_AUX_THRESH_WARM: + ret = kstrtoint(buf, 10, &chg->jeita_aux_thresh_warm); + if (ret < 0) { + count = 0; + break; + } + break; + default: + break; + } + return count; +} + +static int smb2_somc_create_sysfs_entries(struct device *dev) +{ + int i; + int rc = 0; + + for (i = 0; i < ARRAY_SIZE(smb2_somc_attrs); i++) { + rc = device_create_file(dev, &smb2_somc_attrs[i]); + if (rc < 0) { + dev_err(dev, "device_create_file failed rc = %d\n", rc); + goto revert; + } + } + return 0; +revert: + for (i = i - 1; i >= 0; i--) + device_remove_file(dev, &smb2_somc_attrs[i]); + return rc; +} + +static void smb2_somc_remove_sysfs_entries(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(smb2_somc_attrs); i++) + device_remove_file(dev, &smb2_somc_attrs[i]); +} + +#endif static int smb2_probe(struct platform_device *pdev) { struct smb2 *chip; @@ -2246,15 +3320,15 @@ static int smb2_probe(struct platform_device *pdev) return rc; } - rc = smb2_parse_dt(chip); + rc = smblib_init(chg); if (rc < 0) { - pr_err("Couldn't parse device tree rc=%d\n", rc); + pr_err("Smblib_init failed rc=%d\n", rc); goto cleanup; } - rc = smblib_init(chg); + rc = smb2_parse_dt(chip); if (rc < 0) { - pr_err("Smblib_init failed rc=%d\n", rc); + pr_err("Couldn't parse device tree rc=%d\n", rc); goto cleanup; } @@ -2291,6 +3365,17 @@ static int smb2_probe(struct platform_device *pdev) goto cleanup; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chg->xo_clk = devm_clk_get(chg->dev, "xo"); + if (IS_ERR(chg->xo_clk)) { + rc = PTR_ERR(chg->extcon); + dev_err(chg->dev, "failed to get XO buffer handle rc=%d\n", + rc); + goto cleanup; + } + clk_set_rate(chg->xo_clk, 19200000); + +#endif rc = smb2_init_hw(chip); if (rc < 0) { pr_err("Couldn't initialize hardware rc=%d\n", rc); @@ -2348,6 +3433,20 @@ static int smb2_probe(struct platform_device *pdev) smb2_create_debugfs(chip); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + rc = smb2_somc_create_sysfs_entries(chg->dev); + if (rc < 0) { + pr_err("Couldn't create sysfs entries rc=%d\n", rc); + goto cleanup; + } + + rc = somc_usb_register(chg); + if (rc < 0) { + pr_err("somc usb register failed rc = %d\n", rc); + goto cleanup; + } +#endif + rc = smblib_get_prop_usb_present(chg, &val); if (rc < 0) { pr_err("Couldn't get usb present rc=%d\n", rc); @@ -2385,6 +3484,9 @@ static int smb2_probe(struct platform_device *pdev) cleanup: smb2_free_interrupts(chg); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + somc_usb_unregister(chg); +#endif if (chg->batt_psy) power_supply_unregister(chg->batt_psy); if (chg->usb_main_psy) @@ -2411,6 +3513,11 @@ static int smb2_remove(struct platform_device *pdev) struct smb2 *chip = platform_get_drvdata(pdev); struct smb_charger *chg = &chip->chg; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + somc_usb_unregister(chg); + smb2_somc_remove_sysfs_entries(chg->dev); + clk_put(chg->xo_clk); +#endif power_supply_unregister(chg->batt_psy); power_supply_unregister(chg->usb_psy); power_supply_unregister(chg->usb_port_psy); diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index f9d35ea7775bbc72be8298fbfeddb09853d21b1f..0b20974eb9f525beb3b04659132b50629daa9fd0 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -20,10 +25,15 @@ #include #include #include +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#include +#include +#include +#include +#endif #include "smb-lib.h" #include "smb-reg.h" #include "battery.h" -#include "step-chg-jeita.h" #include "storm-watch.h" #define smblib_err(chg, fmt, ...) \ @@ -103,11 +113,46 @@ unlock: return rc; } +static int smblib_get_step_cc_delta(struct smb_charger *chg, int *cc_delta_ua) +{ + int rc, step_state; + u8 stat; + + if (!chg->step_chg_enabled) { + *cc_delta_ua = 0; + return 0; + } + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", + rc); + return rc; + } + + step_state = (stat & STEP_CHARGING_STATUS_MASK) >> + STEP_CHARGING_STATUS_SHIFT; + rc = smblib_get_charge_param(chg, &chg->param.step_cc_delta[step_state], + cc_delta_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc); + return rc; + } + + return 0; +} + static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua) { int rc, cc_minus_ua; u8 stat; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chg->jeita_sw_ctl_en) { + *cc_delta_ua = 0; + return 0; + } +#endif rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n", @@ -121,7 +166,7 @@ static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua) } rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp, - &cc_minus_ua); + &cc_minus_ua); if (rc < 0) { smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc); return rc; @@ -144,6 +189,42 @@ int smblib_icl_override(struct smb_charger *chg, bool override) return rc; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define USB_SWITCH_SEL_USB1 0 +#define USB_SWITCH_SEL_USB2 1 + +static void smblib_select_usb_switch(struct smb_charger *chg, int port) +{ + struct qpnp_pin_cfg pincfg; + + if (gpio_is_valid(chg->usb_switch_sel_gpio)) { + if (port == USB_SWITCH_SEL_USB1) { + if (qpnp_get_pin_config(chg->usb_switch_sel_gpio, + &pincfg)) { + pr_err("qpnp_get_pin_config is fail\n"); + return; + } + pincfg.mode = 1; /* Out */ + pincfg.output_type = 0; /* CMOS */ + pincfg.invert = 0; /* Low */ + pincfg.vin_sel = 0; /* VPH */ + pincfg.out_strength = 1; /* Low */ + pincfg.src_sel = 0; /* GPIO */ + pincfg.master_en = 1; /* Enable */ + + if (qpnp_pin_config(chg->usb_switch_sel_gpio, + &pincfg)) { + pr_err("qpnp_pin_config is fail\n"); + return; + } + } + + gpio_set_value(chg->usb_switch_sel_gpio, port); + dev_info(chg->dev, "select port=%d\n", port); + } +} +#endif + /******************** * REGISTER GETTERS * ********************/ @@ -192,6 +273,7 @@ struct apsd_result { const enum power_supply_type pst; }; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) enum { UNKNOWN, SDP, @@ -246,6 +328,87 @@ static const struct apsd_result const smblib_apsd_results[] = { .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3, }, }; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +enum { + UNKNOWN, + SDP, + CDP, + DCP, + OCP, + FLOAT, + HVDCP2, + HVDCP3, + PD, + MAX_TYPES +}; + +static const struct apsd_result const smblib_apsd_results[] = { + [UNKNOWN] = { + .name = "UNKNOWN_CHARGER", + .bit = 0, + .pst = POWER_SUPPLY_TYPE_UNKNOWN + }, + [SDP] = { + .name = "USB_SDP_CHARGER", + .bit = SDP_CHARGER_BIT, + .pst = POWER_SUPPLY_TYPE_USB + }, + [CDP] = { + .name = "USB_CDP_CHARGER", + .bit = CDP_CHARGER_BIT, + .pst = POWER_SUPPLY_TYPE_USB_CDP + }, + [DCP] = { + .name = "USB_DCP_CHARGER", + .bit = DCP_CHARGER_BIT, + .pst = POWER_SUPPLY_TYPE_USB_DCP + }, + [OCP] = { + .name = "USB_PROPRIETARY_CHARGER", + .bit = OCP_CHARGER_BIT, + .pst = POWER_SUPPLY_TYPE_USB_DCP + }, + [FLOAT] = { + .name = "USB_FLOATED_CHARGER", + .bit = FLOAT_CHARGER_BIT, + .pst = POWER_SUPPLY_TYPE_USB_DCP + }, + [HVDCP2] = { + .name = "USB_HVDCP_CHARGER", + .bit = DCP_CHARGER_BIT | QC_2P0_BIT, + .pst = POWER_SUPPLY_TYPE_USB_HVDCP + }, + [HVDCP3] = { + .name = "USB_HVDCP_3_CHARGER", + .bit = DCP_CHARGER_BIT | QC_3P0_BIT, + .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3, + }, + [PD] = { + .name = "USB_PD_CHARGER", + .bit = 0xff, + .pst = POWER_SUPPLY_TYPE_USB_PD, + }, +}; + +const char *smblib_somc_get_charger_type(struct smb_charger *chg) +{ + const char *charger_type = NULL; + int i; + + for (i = UNKNOWN; i < MAX_TYPES; i++) { + if (smblib_apsd_results[i].bit == + chg->usb_params.apsd_result_bit) { + charger_type = smblib_apsd_results[i].name; + break; + } + } + if (!charger_type) + charger_type = smblib_apsd_results[UNKNOWN].name; + + return charger_type; +} +#endif static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) { @@ -260,8 +423,10 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) } smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat); - if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT)) + if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT)) { + smblib_err(chg, "APSD not done yet.\n"); return result; + } rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat); if (rc < 0) { @@ -374,31 +539,48 @@ int smblib_set_charge_param(struct smb_charger *chg, return rc; } -int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend) +static int step_charge_soc_update(struct smb_charger *chg, int capacity) { int rc = 0; - int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq; - if (suspend && irq) { - if (chg->usb_icl_change_irq_enabled) { - disable_irq_nosync(irq); - chg->usb_icl_change_irq_enabled = false; - } + rc = smblib_set_charge_param(chg, &chg->param.step_soc, capacity); + if (rc < 0) { + smblib_err(chg, "Error in updating soc, rc=%d\n", rc); + return rc; + } + + rc = smblib_write(chg, STEP_CHG_SOC_VBATT_V_UPDATE_REG, + STEP_CHG_SOC_VBATT_V_UPDATE_BIT); + if (rc < 0) { + smblib_err(chg, + "Couldn't set STEP_CHG_SOC_VBATT_V_UPDATE_REG rc=%d\n", + rc); + return rc; } + return rc; +} + +int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend) +{ + int rc = 0; + +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* WA for outbreak of icl charge irq during suspneded */ + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + USBIN_AICL_RERUN_EN_BIT, + suspend ? 0 : USBIN_AICL_RERUN_EN_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't set AICL rerun en bit rc=%d\n", rc); + return rc; + } +#endif rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT, suspend ? USBIN_SUSPEND_BIT : 0); if (rc < 0) smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n", suspend ? "suspend" : "resume", rc); - if (!suspend && irq) { - if (!chg->usb_icl_change_irq_enabled) { - enable_irq(irq); - chg->usb_icl_change_irq_enabled = true; - } - } - return rc; } @@ -490,45 +672,6 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg, /******************** * HELPER FUNCTIONS * ********************/ -static int smblib_request_dpdm(struct smb_charger *chg, bool enable) -{ - int rc = 0; - - /* fetch the DPDM regulator */ - if (!chg->dpdm_reg && of_get_property(chg->dev->of_node, - "dpdm-supply", NULL)) { - chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm"); - if (IS_ERR(chg->dpdm_reg)) { - rc = PTR_ERR(chg->dpdm_reg); - smblib_err(chg, "Couldn't get dpdm regulator rc=%d\n", - rc); - chg->dpdm_reg = NULL; - return rc; - } - } - - if (enable) { - if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) { - smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n"); - rc = regulator_enable(chg->dpdm_reg); - if (rc < 0) - smblib_err(chg, - "Couldn't enable dpdm regulator rc=%d\n", - rc); - } - } else { - if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) { - smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n"); - rc = regulator_disable(chg->dpdm_reg); - if (rc < 0) - smblib_err(chg, - "Couldn't disable dpdm regulator rc=%d\n", - rc); - } - } - - return rc; -} static void smblib_rerun_apsd(struct smb_charger *chg) { @@ -555,17 +698,16 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* if PD is active, APSD is disabled so won't have a valid result */ - if (chg->pd_active) { + if (chg->pd_active) chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; - } else { - /* - * Update real charger type only if its not FLOAT - * detected as as SDP - */ - if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT && - chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) + else chg->real_charger_type = apsd_result->pst; - } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chg->pd_active) + chg->usb_params.apsd_result_bit = 0xff; + else + chg->usb_params.apsd_result_bit = apsd_result->bit; +#endif smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n", apsd_result->name, chg->pd_active); @@ -648,9 +790,13 @@ static void smblib_uusb_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); - rc = smblib_request_dpdm(chg, false); - if (rc < 0) - smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc); + if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) { + smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n"); + rc = regulator_disable(chg->dpdm_reg); + if (rc < 0) + smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n", + rc); + } if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data; @@ -742,9 +888,47 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg) if (!val.intval) return 0; - rc = smblib_request_dpdm(chg, true); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_dbg(chg, PR_SOMC, "start type-c reconnection\n"); + rc = smblib_masked_write(chg, + TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_DISABLE_CMD_BIT, + TYPEC_DISABLE_CMD_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc); + + /* wait for the adapter to turn off VBUS */ + msleep(400); + + rc = smblib_masked_write(chg, + TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_DISABLE_CMD_BIT, 0); if (rc < 0) - smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); + smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc); + + /* wait for type-c detection to complete */ + msleep(200); + smblib_dbg(chg, PR_SOMC, "complete type-c reconnection\n"); + +#endif + /* fetch the DPDM regulator */ + if (!chg->dpdm_reg && of_get_property(chg->dev->of_node, + "dpdm-supply", NULL)) { + chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm"); + if (IS_ERR(chg->dpdm_reg)) { + smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n", + PTR_ERR(chg->dpdm_reg)); + chg->dpdm_reg = NULL; + } + } + + if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) { + smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n"); + rc = regulator_enable(chg->dpdm_reg); + if (rc < 0) + smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n", + rc); + } chg->uusb_apsd_rerun_done = true; smblib_rerun_apsd(chg); @@ -809,12 +993,19 @@ static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count) #define USBIN_150MA 150000 #define USBIN_500MA 500000 #define USBIN_900MA 900000 - +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define USBIN_50MA 50000 +#define USBIN_75MA 75000 +#define USBIN_1000MA 1000000 +#define USBIN_1500MA 1500000 +#define USBIN_3000MA 3000000 +#endif + +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) static int set_sdp_current(struct smb_charger *chg, int icl_ua) { int rc; u8 icl_options; - const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); /* power source is SDP */ switch (icl_ua) { @@ -839,21 +1030,6 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) return -EINVAL; } - if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB && - apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) { - /* - * change the float charger configuration to SDP, if this - * is the case of SDP being detected as FLOAT - */ - rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, - FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't set float ICL options rc=%d\n", - rc); - return rc; - } - } - rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options); if (rc < 0) { @@ -863,6 +1039,7 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) return rc; } +#endif static int get_sdp_current(struct smb_charger *chg, int *icl_ua) { @@ -890,15 +1067,21 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) { int rc = 0; bool override; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + u8 reg; + bool icl_setting_again = false; +#endif /* suspend and return if 25mA or less is requested */ if (icl_ua < USBIN_25MA) return smblib_set_usb_suspend(chg, true); + disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq); if (icl_ua == INT_MAX) goto override_suspend_config; /* configure current */ +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) { rc = set_sdp_current(chg, icl_ua); @@ -914,10 +1097,31 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) goto enable_icl_changed_interrupt; } } +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_dbg(chg, PR_MISC, "set icl %d uA on callback\n", icl_ua); + + rc = smblib_read(chg, USBIN_CMD_IL_REG, ®); + if (rc < 0) { + smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc); + goto enable_icl_changed_interrupt; + } + + if ((reg & USBIN_SUSPEND_BIT) && + (icl_ua > USBIN_75MA)) { + icl_setting_again = true; + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, + USBIN_75MA); + } else { + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, + icl_ua); + } +#endif override_suspend_config: /* determine if override needs to be enforced */ override = true; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (icl_ua == INT_MAX) { /* remove override if no voters - hw defaults is desired */ override = false; @@ -933,6 +1137,7 @@ override_suspend_config: */ override = false; } +#endif /* enforce override */ rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, @@ -950,8 +1155,19 @@ override_suspend_config: smblib_err(chg, "Couldn't resume input rc=%d\n", rc); goto enable_icl_changed_interrupt; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (icl_setting_again) { + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, + icl_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc); + goto enable_icl_changed_interrupt; + } + } +#endif enable_icl_changed_interrupt: + enable_irq(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq); return rc; } @@ -1118,8 +1334,18 @@ static int smblib_hvdcp_enable_vote_callback(struct votable *votable, } /* re-run APSD if HVDCP was detected */ +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (stat & QC_CHARGER_BIT) smblib_rerun_apsd(chg); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (hvdcp_enable) { + vote(chg->usb_icl_votable, HIGH_VOLTAGE_VOTER, true, + chg->high_voltage_icl_ua); + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); + smblib_rerun_apsd(chg); + } +#endif return 0; } @@ -1230,9 +1456,82 @@ static int smblib_typec_irq_disable_vote_callback(struct votable *votable, return 0; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +/***************** + * USB CALLBACKS * + *****************/ +int somc_usb_register(struct smb_charger *chg) +{ + struct usb_somc_params *params = &chg->usb_params; + struct somc_usb_ocp *ocp = ¶ms->ocp; + + memset(&ocp->notification, 0, sizeof(ocp->notification)); + spin_lock_init(&ocp->lock); + + smblib_dbg(chg, PR_SOMC, "somc usb register success\n"); + return 0; +} + +void somc_usb_unregister(struct smb_charger *chg) +{ + ; +} + +#endif + /******************* * VCONN REGULATOR * * *****************/ +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +const char *rdev_get_name(struct regulator_dev *rdev) +{ + if (rdev->constraints && rdev->constraints->name) + return rdev->constraints->name; + else if (rdev->desc->name) + return rdev->desc->name; + else + return ""; +} + +int somc_usb_otg_regulator_register_ocp_notification( + struct regulator_dev *rdev, + struct regulator_ocp_notification *notification) +{ + struct smb_charger *chg = rdev_get_drvdata(rdev); + struct somc_usb_ocp *ocp = &chg->usb_params.ocp; + unsigned long flags; + + spin_lock_irqsave(&ocp->lock, flags); + if (notification) + /* register ocp notification */ + ocp->notification = *notification; + else + /* unregister ocp notification */ + memset(&ocp->notification, 0, sizeof(ocp->notification)); + spin_unlock_irqrestore(&ocp->lock, flags); + + smblib_dbg(chg, PR_SOMC, "%s: registered ocp notification(notify=%p, ctxt=%p)\n", + rdev_get_name(rdev), + ocp->notification.notify, + ocp->notification.ctxt); + + return 0; +} + +static int somc_usb_otg_regulator_ocp_notify(struct smb_charger *chg) +{ + struct somc_usb_ocp *ocp = &chg->usb_params.ocp; + unsigned long flags; + + spin_lock_irqsave(&ocp->lock, flags); + if (ocp->notification.notify) + ocp->notification.notify(ocp->notification.ctxt); + spin_unlock_irqrestore(&ocp->lock, flags); + + return 0; +} + +#endif #define MAX_OTG_SS_TRIES 2 static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev) @@ -1327,110 +1626,71 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev) #define MAX_RETRY 15 #define MIN_DELAY_US 2000 #define MAX_DELAY_US 9000 -static int otg_current[] = {250000, 500000, 1000000, 1500000}; -static int smblib_enable_otg_wa(struct smb_charger *chg) +static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) { + struct smb_charger *chg = rdev_get_drvdata(rdev); + int rc, retry_count = 0, min_delay = MIN_DELAY_US; u8 stat; - int rc, i, retry_count = 0, min_delay = MIN_DELAY_US; - - for (i = 0; i < ARRAY_SIZE(otg_current); i++) { - smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n", - otg_current[i]); - rc = smblib_set_charge_param(chg, &chg->param.otg_cl, - otg_current[i]); - if (rc < 0) { - smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc); - return rc; - } - - rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc); - return rc; - } - retry_count = 0; - min_delay = MIN_DELAY_US; - do { - usleep_range(min_delay, min_delay + 100); + smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n"); + rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, + ENG_BUCKBOOST_HALT1_8_MODE_BIT, + ENG_BUCKBOOST_HALT1_8_MODE_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", + rc); + return rc; + } + + smblib_dbg(chg, PR_OTG, "enabling OTG\n"); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_select_usb_switch(chg, USB_SWITCH_SEL_USB1); +#endif + rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc); + return rc; + } + + if (chg->wa_flags & OTG_WA) { + /* check for softstart */ + do { + usleep_range(min_delay, min_delay + 100); rc = smblib_read(chg, OTG_STATUS_REG, &stat); if (rc < 0) { - smblib_err(chg, "Couldn't read OTG status rc=%d\n", - rc); + smblib_err(chg, + "Couldn't read OTG status rc=%d\n", + rc); goto out; } if (stat & BOOST_SOFTSTART_DONE_BIT) { rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chg->otg_cl_ua); - if (rc < 0) { - smblib_err(chg, "Couldn't set otg limit rc=%d\n", - rc); - goto out; - } + if (rc < 0) + smblib_err(chg, + "Couldn't set otg limit\n"); break; } + /* increase the delay for following iterations */ if (retry_count > 5) min_delay = MAX_DELAY_US; - } while (retry_count++ < MAX_RETRY); if (retry_count >= MAX_RETRY) { - smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n", - otg_current[i]); - rc = smblib_write(chg, CMD_OTG_REG, 0); - if (rc < 0) { - smblib_err(chg, "disable OTG rc=%d\n", rc); - goto out; - } - } else { - smblib_dbg(chg, PR_OTG, "OTG enabled\n"); - return 0; + smblib_dbg(chg, PR_OTG, "Boost Softstart not done\n"); + goto out; } } - if (i == ARRAY_SIZE(otg_current)) { - rc = -EINVAL; - goto out; - } - return 0; out: + /* disable OTG if softstart failed */ smblib_write(chg, CMD_OTG_REG, 0); return rc; } -static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev) -{ - struct smb_charger *chg = rdev_get_drvdata(rdev); - int rc; - - smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n"); - rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG, - ENG_BUCKBOOST_HALT1_8_MODE_BIT, - ENG_BUCKBOOST_HALT1_8_MODE_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", - rc); - return rc; - } - - smblib_dbg(chg, PR_OTG, "enabling OTG\n"); - - if (chg->wa_flags & OTG_WA) { - rc = smblib_enable_otg_wa(chg); - if (rc < 0) - smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc); - } else { - rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT); - if (rc < 0) - smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc); - } - - return rc; -} - int smblib_vbus_regulator_enable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); @@ -1526,6 +1786,52 @@ int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev) * BATT PSY GETTERS * ********************/ +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +int smblib_get_prop_charging_enabled(struct smb_charger *chg, + union power_supply_propval *val) +{ + smblib_get_prop_input_suspend(chg, val); + val->intval = val->intval ? 0 : 1; + return 0; +} + +int smblib_get_prop_charge_full_design(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, val); + if (rc < 0) { + smblib_err(chg, "Couldn't get prop charge_full_design rc=%d\n", rc); + return rc; + } + + return 0; +} + +int smblib_get_prop_charge_full(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_CHARGE_FULL, val); + if (rc < 0) { + smblib_err(chg, "Couldn't get prop charge_full rc=%d\n", rc); + return rc; + } + + return 0; +} + +#endif int smblib_get_prop_input_suspend(struct smb_charger *chg, union power_supply_propval *val) { @@ -1558,24 +1864,66 @@ int smblib_get_prop_batt_capacity(struct smb_charger *chg, { int rc = -EINVAL; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (chg->fake_capacity >= 0) { val->intval = chg->fake_capacity; return 0; } +#endif if (chg->bms_psy) rc = power_supply_get_property(chg->bms_psy, POWER_SUPPLY_PROP_CAPACITY, val); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (rc < 0) { + smblib_err(chg, "Couldn't get prop capacity rc=%d\n", rc); + } else { + if (val->intval <= 0 && chg->low_batt_shutdown_enabled) { + smblib_somc_set_low_batt_suspend_en(chg); + chg->fake_capacity = -EINVAL; + } + + if (chg->fake_capacity >= 0) + val->intval = chg->fake_capacity; + } + + smblib_somc_lrc_check(chg); + val->intval = smblib_somc_lrc_get_capacity(chg, val->intval); +#endif return rc; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +enum { + TEMP_CONDITION_DEFAULT = 0, + TEMP_CONDITION_COLD, + TEMP_CONDITION_COOL, + TEMP_CONDITION_NORMAL, + TEMP_CONDITION_WARM, + TEMP_CONDITION_HOT, +}; +enum { + FAKED_STATUS_NONE = 0, + FAKED_STATUS_TYPEC_EN_DIS_ACTIVE, + FAKED_STATUS_SMART, + FAKED_STATUS_DURING_WARM_FULL, + FAKED_STATUS_RB_WA, + FAKED_STATUS_WA_FOR_WARM_FULL, +}; +#endif int smblib_get_prop_batt_status(struct smb_charger *chg, union power_supply_propval *val) { union power_supply_propval pval = {0, }; - bool usb_online, dc_online, qnovo_en; - u8 stat, pt_en_cmd; + bool usb_online, dc_online; + u8 stat; int rc; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int i = 0; + int votabled, smart_votabled = 0, other_votabled = 0; + char *clients[NUM_MAX_CLIENTS]; + int num_clients = 0; +#endif rc = smblib_get_prop_usb_online(chg, &pval); if (rc < 0) { @@ -1611,6 +1959,9 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, val->intval = POWER_SUPPLY_STATUS_DISCHARGING; break; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chg->faked_status = FAKED_STATUS_NONE; +#endif return rc; } @@ -1634,6 +1985,65 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, break; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chg->typec_en_dis_active || chg->duration_fake_charging) { + smblib_dbg(chg, PR_MISC, + "Fake charging during type-c en/dis is active (%d)\n", + val->intval); + val->intval = chg->status_before_typec_en_dis_active; + chg->faked_status = FAKED_STATUS_TYPEC_EN_DIS_ACTIVE; + return 0; + } + + num_clients = somc_get_vote_clients(chg->chg_disable_votable, clients); + for (i = 0; i < num_clients; i++) { + votabled = get_client_vote(chg->chg_disable_votable, + clients[i]); + if (strcmp(clients[i], BATTCHG_SMART_EN_VOTER) == 0) + smart_votabled = votabled; + else if (!other_votabled) + other_votabled = votabled; + } + if (smart_votabled && !other_votabled) { + smblib_dbg(chg, PR_MISC, + "Fake charging due to smart charge (%d)\n", + val->intval); + val->intval = POWER_SUPPLY_STATUS_CHARGING; + chg->faked_status = FAKED_STATUS_SMART; + return 0; + } + + if (val->intval == POWER_SUPPLY_STATUS_FULL && + chg->jeita_sw_ctl_en && + chg->jeita_synth_temp_condition == TEMP_CONDITION_WARM) { + smblib_dbg(chg, PR_MISC, + "Fake charging during Warm and FULL (%d)\n", + val->intval); + val->intval = POWER_SUPPLY_STATUS_CHARGING; + chg->faked_status = FAKED_STATUS_DURING_WARM_FULL; + return 0; + } + + if (chg->jeita_rb_warm_hi_vbatt_en && + !get_effective_result(chg->chg_disable_votable)) { + smblib_dbg(chg, PR_MISC, + "Fake charging due to Reverse Boost WA (%d)\n", + val->intval); + val->intval = POWER_SUPPLY_STATUS_CHARGING; + chg->faked_status = FAKED_STATUS_RB_WA; + return 0; + } + + if (chg->jeita_keep_fake_charging) { + smblib_dbg(chg, PR_MISC, + "Fake charging during WA for Warm/FULL (%d)\n", + val->intval); + val->intval = POWER_SUPPLY_STATUS_CHARGING; + chg->faked_status = FAKED_STATUS_WA_FOR_WARM_FULL; + return 0; + } + chg->faked_status = FAKED_STATUS_NONE; +#endif if (val->intval != POWER_SUPPLY_STATUS_CHARGING) return 0; @@ -1642,22 +2052,11 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n", rc); return rc; - } + } stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT | ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT; - - rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &pt_en_cmd); - if (rc < 0) { - smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD_REG rc=%d\n", - rc); - return rc; - } - - qnovo_en = (bool)(pt_en_cmd & QNOVO_PT_ENABLE_CMD_BIT); - - /* ignore stat7 when qnovo is enabled */ - if (!qnovo_en && !stat) + if (!stat) val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; return 0; @@ -1712,7 +2111,14 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n", stat); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) { +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT && + (!chg->jeita_sw_ctl_en || + chg->jeita_synth_temp_condition != TEMP_CONDITION_WARM)) { +#endif rc = smblib_get_prop_batt_voltage_now(chg, &pval); if (!rc) { /* @@ -1729,6 +2135,7 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, } } +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT) val->intval = POWER_SUPPLY_HEALTH_COLD; else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT) @@ -1739,6 +2146,39 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, val->intval = POWER_SUPPLY_HEALTH_WARM; else val->intval = POWER_SUPPLY_HEALTH_GOOD; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chg->jeita_sw_ctl_en) { + switch (chg->jeita_synth_temp_condition) { + case TEMP_CONDITION_HOT: + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; + break; + case TEMP_CONDITION_WARM: + val->intval = POWER_SUPPLY_HEALTH_WARM; + break; + case TEMP_CONDITION_COOL: + val->intval = POWER_SUPPLY_HEALTH_COOL; + break; + case TEMP_CONDITION_COLD: + val->intval = POWER_SUPPLY_HEALTH_COLD; + break; + default: + val->intval = POWER_SUPPLY_HEALTH_GOOD; + break; + } + } else { + if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT) + val->intval = POWER_SUPPLY_HEALTH_COLD; + else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT) + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; + else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT) + val->intval = POWER_SUPPLY_HEALTH_COOL; + else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT) + val->intval = POWER_SUPPLY_HEALTH_WARM; + else + val->intval = POWER_SUPPLY_HEALTH_GOOD; + } +#endif done: return rc; @@ -1810,6 +2250,30 @@ int smblib_get_prop_batt_temp(struct smb_charger *chg, return rc; } +int smblib_get_prop_step_chg_step(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + u8 stat; + + if (!chg->step_chg_enabled) { + val->intval = -1; + return 0; + } + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", + rc); + return rc; + } + + val->intval = (stat & STEP_CHARGING_STATUS_MASK) >> + STEP_CHARGING_STATUS_SHIFT; + + return rc; +} + int smblib_get_prop_batt_charge_done(struct smb_charger *chg, union power_supply_propval *val) { @@ -1862,6 +2326,19 @@ int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, * BATTERY PSY SETTERS * ***********************/ +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +int smblib_set_prop_charging_enabled(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc; + union power_supply_propval tmp = *val; + + tmp.intval = tmp.intval ? 0 : 1; + rc = smblib_set_prop_input_suspend(chg, &tmp); + return rc; +} + +#endif int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val) { @@ -1899,6 +2376,7 @@ int smblib_set_prop_batt_capacity(struct smb_charger *chg, int smblib_set_prop_system_temp_level(struct smb_charger *chg, const union power_supply_propval *val) { +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (val->intval < 0) return -EINVAL; @@ -1923,6 +2401,18 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg, vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true, chg->thermal_mitigation[chg->system_temp_level]); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_dbg(chg, PR_MISC, "Changed Thernal LV from %d to %d\n", + chg->system_temp_level, val->intval); + if (val->intval < 0) + return -EINVAL; + + chg->system_temp_level = val->intval; + + smblib_somc_thermal_fcc_change(chg); + smblib_somc_thermal_icl_change(chg); +#endif return 0; } @@ -2068,29 +2558,6 @@ int smblib_dp_dm(struct smb_charger *chg, int val) return rc; } -int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable) -{ - int rc; - u8 mask; - - /* - * Disable h/w base JEITA compensation if s/w JEITA is enabled - */ - mask = JEITA_EN_COLD_SL_FCV_BIT - | JEITA_EN_HOT_SL_FCV_BIT - | JEITA_EN_HOT_SL_CCC_BIT - | JEITA_EN_COLD_SL_CCC_BIT, - rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask, - disable ? 0 : mask); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't configure s/w jeita rc=%d\n", - rc); - return rc; - } - return 0; -} - /******************* * DC PSY GETTERS * *******************/ @@ -2177,17 +2644,45 @@ int smblib_get_prop_usb_present(struct smb_charger *chg, return 0; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define SDP_CURRENT_SUSPENDED 2000 +#endif int smblib_get_prop_usb_online(struct smb_charger *chg, union power_supply_propval *val) { int rc = 0; u8 stat; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int org_online; + int sdp_current; + + if (get_client_vote(chg->usb_icl_votable, LOW_BATT_EN_VOTER) == 0) { + val->intval = false; + return rc; + } + if (get_client_vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER) == 0) { + val->intval = false; + return rc; + } + sdp_current = get_client_vote(chg->usb_icl_votable, USB_PSY_VOTER); + if (sdp_current >= 0 && sdp_current <= SDP_CURRENT_SUSPENDED) { + val->intval = false; + return rc; + } +#endif if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) { val->intval = false; return rc; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chg->typec_en_dis_active) { + val->intval = true; + return rc; + } + +#endif rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", @@ -2199,6 +2694,18 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, val->intval = (stat & USE_USBIN_BIT) && (stat & VALID_INPUT_POWER_SOURCE_STS_BIT); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + org_online = val->intval; + rc = smblib_get_prop_usb_present(chg, val); + if (rc < 0) { + smblib_err(chg, "Couldn't get present rc=%d\n", rc); + return rc; + } + if (!!val->intval != !!org_online) + smblib_dbg(chg, PR_MISC, + "online mismatch: ret=%d, POWER_PATH_STATUS=0x%02x\n", + val->intval, stat); +#endif return rc; } @@ -2208,10 +2715,12 @@ int smblib_get_prop_usb_voltage_max(struct smb_charger *chg, switch (chg->real_charger_type) { case POWER_SUPPLY_TYPE_USB_HVDCP: case POWER_SUPPLY_TYPE_USB_PD: - if (chg->smb_version == PM660_SUBTYPE) - val->intval = MICRO_9V; - else - val->intval = MICRO_12V; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) + val->intval = MICRO_12V; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + val->intval = MICRO_9V; +#endif break; default: val->intval = MICRO_5V; @@ -2259,6 +2768,26 @@ int smblib_get_prop_usb_current_now(struct smb_charger *chg, return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval); } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +int smblib_get_prop_skin_temp(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc = 0; + + if (!chg->iio.skin_temp_chan || + PTR_ERR(chg->iio.skin_temp_chan) == -EPROBE_DEFER) + chg->iio.skin_temp_chan = iio_channel_get(chg->dev, + "skin_temp"); + + if (IS_ERR(chg->iio.skin_temp_chan)) + return PTR_ERR(chg->iio.skin_temp_chan); + + rc = iio_read_channel_processed(chg->iio.skin_temp_chan, &val->intval); + val->intval /= 100; + return rc; +} + +#endif int smblib_get_prop_charger_temp(struct smb_charger *chg, union power_supply_propval *val) { @@ -2417,9 +2946,16 @@ int smblib_get_prop_input_current_settled(struct smb_charger *chg, int smblib_get_prop_input_voltage_settled(struct smb_charger *chg, union power_supply_propval *val) { + const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); int rc, pulses; - switch (chg->real_charger_type) { + val->intval = MICRO_5V; + if (apsd_result == NULL) { + smblib_err(chg, "APSD result is NULL\n"); + return 0; + } + + switch (apsd_result->pst) { case POWER_SUPPLY_TYPE_USB_HVDCP_3: rc = smblib_get_pulse_cnt(chg, &pulses); if (rc < 0) { @@ -2429,9 +2965,6 @@ int smblib_get_prop_input_voltage_settled(struct smb_charger *chg, } val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses; break; - case POWER_SUPPLY_TYPE_USB_PD: - val->intval = chg->voltage_min_uv; - break; default: val->intval = MICRO_5V; break; @@ -2494,31 +3027,6 @@ int smblib_get_prop_die_health(struct smb_charger *chg, return 0; } -#define SDP_CURRENT_UA 500000 -#define CDP_CURRENT_UA 1500000 -#define DCP_CURRENT_UA 1500000 -#define HVDCP_CURRENT_UA 3000000 -#define TYPEC_DEFAULT_CURRENT_UA 900000 -#define TYPEC_MEDIUM_CURRENT_UA 1500000 -#define TYPEC_HIGH_CURRENT_UA 3000000 -static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode) -{ - int rp_ua; - - switch (typec_mode) { - case POWER_SUPPLY_TYPEC_SOURCE_HIGH: - rp_ua = TYPEC_HIGH_CURRENT_UA; - break; - case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: - case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: - /* fall through */ - default: - rp_ua = DCP_CURRENT_UA; - } - - return rp_ua; -} - /******************* * USB PSY SETTERS * * *****************/ @@ -2536,54 +3044,38 @@ int smblib_set_prop_pd_current_max(struct smb_charger *chg, return rc; } -static int smblib_handle_usb_current(struct smb_charger *chg, - int usb_current) +int smblib_set_prop_sdp_current_max(struct smb_charger *chg, + const union power_supply_propval *val) { - int rc = 0, rp_ua, typec_mode; + int rc = 0; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int sdp_current; +#endif - if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) { - if (usb_current == -ETIMEDOUT) { - /* - * Valid FLOAT charger, report the current based - * of Rp - */ - typec_mode = smblib_get_prop_typec_mode(chg); - rp_ua = get_rp_based_dcp_current(chg, typec_mode); - rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, - true, rp_ua); - if (rc < 0) - return rc; - } else { - /* - * FLOAT charger detected as SDP by USB driver, - * charge with the requested current and update the - * real_charger_type - */ - chg->real_charger_type = POWER_SUPPLY_TYPE_USB; - rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, - true, usb_current); - if (rc < 0) - return rc; - rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, - false, 0); - if (rc < 0) - return rc; + if (!chg->pd_active) { +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) + rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, + true, val->intval); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + switch (val->intval) { + case USBIN_100MA: + case USBIN_150MA: + case USBIN_500MA: + sdp_current = val->intval - USBIN_25MA; + break; + case USBIN_900MA: + sdp_current = val->intval - USBIN_50MA; + break; + default: + sdp_current = val->intval; } - } else { rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, - true, usb_current); - } - - return rc; -} - -int smblib_set_prop_sdp_current_max(struct smb_charger *chg, - const union power_supply_propval *val) -{ - int rc = 0; + true, sdp_current); - if (!chg->pd_active) { - rc = smblib_handle_usb_current(chg, val->intval); + /* The vote by USB_PSY_VOTER may change online */ + power_supply_changed(chg->usb_psy); +#endif } else if (chg->system_suspend_supported) { if (val->intval <= USBIN_25MA) rc = vote(chg->usb_icl_votable, @@ -2653,6 +3145,12 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, } } + if (val->intval == POWER_SUPPLY_TYPEC_PR_SINK || + val->intval == POWER_SUPPLY_TYPEC_PR_SOURCE) { + smblib_err(chg, "power role set to SINK or SRC, sleep 120ms\n"); + msleep(120); + } + rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, TYPEC_POWER_ROLE_CMD_MASK, power_role); if (rc < 0) { @@ -2679,7 +3177,6 @@ int smblib_set_prop_pd_voltage_min(struct smb_charger *chg, } chg->voltage_min_uv = min_uv; - power_supply_changed(chg->usb_main_psy); return rc; } @@ -2698,6 +3195,15 @@ int smblib_set_prop_pd_voltage_max(struct smb_charger *chg, } chg->voltage_max_uv = max_uv; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chg->voltage_max_uv > MICRO_5V) + vote(chg->usb_icl_votable, HIGH_VOLTAGE_VOTER, + true, chg->high_voltage_icl_ua); + else + vote(chg->usb_icl_votable, HIGH_VOLTAGE_VOTER, + false, 0); + smblib_somc_thermal_icl_change(chg); +#endif return rc; } @@ -2795,6 +3301,9 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, } smblib_update_usb_type(chg); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_somc_thermal_icl_change(chg); +#endif power_supply_changed(chg->usb_psy); return rc; } @@ -2967,72 +3476,46 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, return rc; } -static int smblib_recover_from_soft_jeita(struct smb_charger *chg) -{ - u8 stat_1, stat_2; - int rc; - - rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1); - if (rc < 0) { - smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", - rc); - return rc; - } - - rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2); - if (rc < 0) { - smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n", - rc); - return rc; - } - - if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) && - ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) { - /* - * We are moving from JEITA soft -> Normal and charging - * is terminated - */ - rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0); - if (rc < 0) { - smblib_err(chg, "Couldn't disable charging rc=%d\n", - rc); - return rc; - } - rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, - CHARGING_ENABLE_CMD_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't enable charging rc=%d\n", - rc); - return rc; - } - } - - chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK; - - return 0; -} - /*********************** * USB MAIN PSY GETTERS * *************************/ int smblib_get_prop_fcc_delta(struct smb_charger *chg, - union power_supply_propval *val) + union power_supply_propval *val) { - int rc, jeita_cc_delta_ua = 0; + int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0; + + rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc); + step_cc_delta_ua = 0; + } else { + hw_cc_delta_ua = step_cc_delta_ua; + } rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua); if (rc < 0) { smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc); jeita_cc_delta_ua = 0; + } else if (jeita_cc_delta_ua < 0) { + /* HW will take the min between JEITA and step charge */ + hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua); } - val->intval = jeita_cc_delta_ua; + val->intval = hw_cc_delta_ua; return 0; } /*********************** * USB MAIN PSY SETTERS * *************************/ + +#define SDP_CURRENT_UA 500000 +#define CDP_CURRENT_UA 1500000 +#define DCP_CURRENT_UA 1500000 +#define HVDCP_CURRENT_UA 3000000 +#define TYPEC_DEFAULT_CURRENT_UA 900000 +#define TYPEC_MEDIUM_CURRENT_UA 1500000 +#define TYPEC_HIGH_CURRENT_UA 3000000 int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua) { @@ -3199,19 +3682,69 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data) return IRQ_HANDLED; } -irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data) +irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + if (chg->step_chg_enabled) + rerun_election(chg->fcc_votable); + + return IRQ_HANDLED; +} + +irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + if (chg->step_chg_enabled) + rerun_election(chg->fcc_votable); + + return IRQ_HANDLED; +} + +#define STEP_SOC_REQ_MS 3000 +irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; int rc; + union power_supply_propval pval = {0, }; - rc = smblib_recover_from_soft_jeita(chg); - if (rc < 0) { - smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n", - rc); + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + if (!chg->bms_psy) { + schedule_delayed_work(&chg->step_soc_req_work, + msecs_to_jiffies(STEP_SOC_REQ_MS)); return IRQ_HANDLED; } + rc = smblib_get_prop_batt_capacity(chg, &pval); + if (rc < 0) + smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc); + else + step_charge_soc_update(chg, pval.intval); + + return IRQ_HANDLED; +} + +irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_dbg(chg, PR_SOMC, "IRQ: %s\n", irq_data->name); + if (chg->jeita_sw_ctl_en) { + cancel_delayed_work_sync(&chg->jeita_work); + schedule_delayed_work(&chg->jeita_work, msecs_to_jiffies(0)); + } +#endif rerun_election(chg->fcc_votable); power_supply_changed(chg->batt_psy); return IRQ_HANDLED; @@ -3242,8 +3775,20 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data) struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; struct storm_watch *wdata; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + const struct apsd_result *apsd_result = smblib_update_usb_type(chg); +#endif smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* ESD workaround */ + if (!chg->typec_en_dis_active && (apsd_result->bit & QC_2P0_BIT)) { + smblib_dbg(chg, PR_SOMC, "rerun APSD for ESD WA\n"); + smblib_masked_write(chg, CMD_APSD_REG, APSD_RERUN_BIT, + APSD_RERUN_BIT); + return IRQ_HANDLED; + } +#endif if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data) return IRQ_HANDLED; @@ -3305,6 +3850,10 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg) } #define PL_DELAY_MS 30000 +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define REMOVAL_DELAY_MS 2000 +#define REMOVAL_WAKE_PERIOD (3 * HZ) +#endif void smblib_usb_plugin_locked(struct smb_charger *chg) { int rc; @@ -3323,10 +3872,42 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V : chg->chg_freq.freq_removal); + /* fetch the DPDM regulator */ + if (!chg->dpdm_reg && of_get_property(chg->dev->of_node, + "dpdm-supply", NULL)) { + chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm"); + if (IS_ERR(chg->dpdm_reg)) { + smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n", + PTR_ERR(chg->dpdm_reg)); + chg->dpdm_reg = NULL; + } + } + +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chg->jeita_sw_ctl_en) { + cancel_delayed_work_sync(&chg->jeita_work); + schedule_delayed_work(&chg->jeita_work, msecs_to_jiffies(0)); + } + +#endif if (vbus_rising) { - rc = smblib_request_dpdm(chg, true); - if (rc < 0) - smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_cc2_sink_removal_exit(chg); + + if (chg->typec_en_dis_active) { + smblib_dbg(chg, PR_SOMC, + "start fake charging by typec_en_dis_active\n"); + schedule_work(&chg->fake_charging_work); + } + smblib_select_usb_switch(chg, USB_SWITCH_SEL_USB1); +#endif + if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) { + smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n"); + rc = regulator_enable(chg->dpdm_reg); + if (rc < 0) + smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n", + rc); + } /* Schedule work to enable parallel charger */ vote(chg->awake_votable, PL_DELAY_VOTER, true, 0); @@ -3346,9 +3927,31 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) } } - rc = smblib_request_dpdm(chg, false); - if (rc < 0) - smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) { + smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n"); + rc = regulator_disable(chg->dpdm_reg); + if (rc < 0) + smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n", + rc); + } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_somc_lrc_check(chg); + wake_lock_timeout( + &chg->usb_removal_wakelock.lock, REMOVAL_WAKE_PERIOD); + schedule_delayed_work(&chg->usb_removal_work, + msecs_to_jiffies(REMOVAL_DELAY_MS)); + + mutex_lock(&chg->xo_lock); + if (chg->xo_holded) { + clk_disable_unprepare(chg->xo_clk); + chg->xo_holded = false; + smblib_dbg(chg, PR_SOMC, + "release xo clock due to charger dettached\n"); + } + mutex_unlock(&chg->xo_lock); + if (chg->pd_hard_reset) + smblib_cc2_sink_removal_enter(chg); +#endif } if (chg->micro_usb_mode) @@ -3365,9 +3968,11 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data) struct smb_charger *chg = irq_data->parent_data; mutex_lock(&chg->lock); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (chg->pd_hard_reset) smblib_usb_plugin_hard_reset_locked(chg); else +#endif smblib_usb_plugin_locked(chg); mutex_unlock(&chg->lock); return IRQ_HANDLED; @@ -3531,7 +4136,9 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, bool rising, bool qc_charger) { +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); +#endif /* Hold off PD only until hvdcp 2.0 detection timeout */ if (rising) { @@ -3542,6 +4149,7 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, if (qc_charger) vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) /* * HVDCP detection timeout done * If adapter is not QC2.0/QC3.0 - it is a plain old DCP. @@ -3550,6 +4158,7 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, /* enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua); +#endif } smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n", @@ -3569,6 +4178,25 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, rising ? "rising" : "falling"); } +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) +static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode) +{ + int rp_ua; + + switch (typec_mode) { + case POWER_SUPPLY_TYPEC_SOURCE_HIGH: + rp_ua = TYPEC_HIGH_CURRENT_UA; + break; + case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: + case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: + /* fall through */ + default: + rp_ua = DCP_CURRENT_UA; + } + + return rp_ua; +} + static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) { int typec_mode; @@ -3594,17 +4222,11 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000); break; case POWER_SUPPLY_TYPE_USB_DCP: + case POWER_SUPPLY_TYPE_USB_FLOAT: typec_mode = smblib_get_prop_typec_mode(chg); rp_ua = get_rp_based_dcp_current(chg, typec_mode); vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua); break; - case POWER_SUPPLY_TYPE_USB_FLOAT: - /* - * limit ICL to 100mA, the USB driver will enumerate to check - * if this is a SDP and appropriately set the current - */ - vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000); - break; case POWER_SUPPLY_TYPE_USB_HVDCP: case POWER_SUPPLY_TYPE_USB_HVDCP_3: vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000); @@ -3615,32 +4237,54 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) break; } } - -static void smblib_notify_extcon_props(struct smb_charger *chg) -{ - union power_supply_propval val; - - smblib_get_prop_typec_cc_orientation(chg, &val); - extcon_set_cable_state_(chg->extcon, EXTCON_USB_CC, - (val.intval == 2) ? 1 : 0); - extcon_set_cable_state_(chg->extcon, EXTCON_USB_SPEED, true); -} - -static void smblib_notify_device_mode(struct smb_charger *chg, bool enable) -{ - if (enable) - smblib_notify_extcon_props(chg); - - extcon_set_cable_state_(chg->extcon, EXTCON_USB, enable); -} - -static void smblib_notify_usb_host(struct smb_charger *chg, bool enable) +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +static void smblib_somc_force_legacy_icl(struct smb_charger *chg, + u8 apsd_result_bit) { - if (enable) - smblib_notify_extcon_props(chg); + /* while PD is active it should have complete ICL control */ + if (chg->pd_active) { + smblib_dbg(chg, PR_SOMC, + "PD is active, does not set ICL by APSD result\n"); + return; + } - extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, enable); + switch (apsd_result_bit) { + case SDP_CHARGER_BIT: + if (!is_client_vote_enabled(chg->usb_icl_votable, + USB_PSY_VOTER)) + vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 0); + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); + break; + case CDP_CHARGER_BIT: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, + USBIN_1500MA); + break; + case DCP_CHARGER_BIT: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, + chg->dcp_icl_ua != -EINVAL ? + chg->dcp_icl_ua : USBIN_1500MA); + break; + case OCP_CHARGER_BIT: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, + USBIN_1000MA); + break; + case FLOAT_CHARGER_BIT: + if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, + USBIN_500MA); + else + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, + USBIN_1500MA); + break; + case 0: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 0); + break; + default: + break; + } } +#endif #define HVDCP_DET_MS 2500 static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) @@ -3653,7 +4297,12 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) apsd_result = smblib_update_usb_type(chg); if (!chg->typec_legacy_valid) +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) smblib_force_legacy_icl(chg, apsd_result->pst); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_somc_force_legacy_icl(chg, apsd_result->bit); +#endif switch (apsd_result->bit) { case SDP_CHARGER_BIT: @@ -3661,8 +4310,6 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) if (chg->micro_usb_mode) extcon_set_cable_state_(chg->extcon, EXTCON_USB, true); - if (chg->use_extcon) - smblib_notify_device_mode(chg, true); case OCP_CHARGER_BIT: case FLOAT_CHARGER_BIT: /* if not DCP then no hvdcp timeout happens, Enable pd here. */ @@ -3678,6 +4325,19 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) break; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (apsd_result->bit != SDP_CHARGER_BIT && + apsd_result->bit != CDP_CHARGER_BIT) { + mutex_lock(&chg->xo_lock); + if (!chg->xo_holded) { + clk_prepare_enable(chg->xo_clk); + chg->xo_holded = true; + smblib_dbg(chg, PR_SOMC, + "hold xo clock due to charger attached\n"); + } + mutex_unlock(&chg->xo_lock); + } +#endif smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n", apsd_result->name); } @@ -3689,6 +4349,13 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) int rc = 0; u8 stat; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (chg->typec_en_dis_active) { + smblib_dbg(chg, PR_SOMC, + "ignored handler during typec_en_dis_active\n"); + return IRQ_HANDLED; + } +#endif rc = smblib_read(chg, APSD_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc); @@ -3728,6 +4395,10 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) smblib_hvdcp_adaptive_voltage_change(chg); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_somc_thermal_icl_change(chg); + +#endif power_supply_changed(chg->usb_psy); rc = smblib_read(chg, APSD_STATUS_REG, &stat); @@ -3740,6 +4411,19 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) return IRQ_HANDLED; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +static void smblib_somc_typec_cur_source(struct smb_charger *chg, bool en180UA) +{ + int rc; + /* change CUR_SOURCE to advertise current */ + rc = smblib_masked_write(chg, TYPE_C_CFG_2_REG, + EN_80UA_180UA_CUR_SOURCE_BIT, + en180UA ? EN_80UA_180UA_CUR_SOURCE_BIT: 0); + if (rc < 0) + dev_err(chg->dev, "Couldn't change cur source rc=%d\n", rc); +} + +#endif static void typec_sink_insertion(struct smb_charger *chg) { /* when a sink is inserted we should not wait on hvdcp timeout to @@ -3747,10 +4431,9 @@ static void typec_sink_insertion(struct smb_charger *chg) */ vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, false, 0); - if (chg->use_extcon) { - smblib_notify_usb_host(chg, true); - chg->otg_present = true; - } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_somc_typec_cur_source(chg, false); +#endif } static void typec_sink_removal(struct smb_charger *chg) @@ -3758,6 +4441,9 @@ static void typec_sink_removal(struct smb_charger *chg) smblib_set_charge_param(chg, &chg->param.freq_boost, chg->chg_freq.freq_above_otg_threshold); chg->boost_current_ua = 0; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + smblib_somc_typec_cur_source(chg, true); +#endif } static void smblib_handle_typec_removal(struct smb_charger *chg) @@ -3768,9 +4454,13 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) chg->cc2_detach_wa_active = false; - rc = smblib_request_dpdm(chg, false); - if (rc < 0) - smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) { + smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n"); + rc = regulator_disable(chg->dpdm_reg); + if (rc < 0) + smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n", + rc); + } if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data; @@ -3791,12 +4481,20 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->hvdcp_detect_work); /* reset input current limit voters */ +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 0); +#endif vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); vote(chg->usb_icl_votable, DCP_VOTER, false, 0); vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + vote(chg->usb_icl_votable, HIGH_VOLTAGE_VOTER, false, 0); +#endif /* reset hvdcp voters */ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0); @@ -3827,13 +4525,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) chg->pd_hard_reset = 0; chg->typec_legacy_valid = false; - /* write back the default FLOAT charger configuration */ - rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, - (u8)FLOAT_OPTIONS_MASK, chg->float_cfg); - if (rc < 0) - smblib_err(chg, "Couldn't write float charger options rc=%d\n", - rc); - /* reset back to 120mS tCC debounce */ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0); if (rc < 0) @@ -3898,15 +4589,13 @@ unlock: rc); typec_sink_removal(chg); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) smblib_update_usb_type(chg); - - if (chg->use_extcon) { - if (chg->otg_present) - smblib_notify_usb_host(chg, false); - else - smblib_notify_device_mode(chg, false); - } - chg->otg_present = false; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + chg->real_charger_type = POWER_SUPPLY_TYPE_UNKNOWN; + chg->usb_params.apsd_result_bit = 0; +#endif } static void smblib_handle_typec_insertion(struct smb_charger *chg) @@ -3921,16 +4610,14 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg) smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n", rc); - if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) { + if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) typec_sink_insertion(chg); - } else { - rc = smblib_request_dpdm(chg, true); - if (rc < 0) - smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); + else typec_sink_removal(chg); - } + } +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) { int rp_ua; @@ -3940,24 +4627,6 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT)) return; - /* - * if APSD indicates FLOAT and the USB stack had detected SDP, - * do not respond to Rp changes as we do not confirm that its - * a legacy cable - */ - if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) - return; - /* - * We want the ICL vote @ 100mA for a FLOAT charger - * until the detection by the USB stack is complete. - * Ignore the Rp changes unless there is a - * pre-existing valid vote. - */ - if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT && - get_client_vote(chg->usb_icl_votable, - LEGACY_UNKNOWN_VOTER) <= 100000) - return; - /* * handle Rp change for DCP/FLOAT/OCP. * Update the current only if the Rp is different from @@ -3969,6 +4638,7 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) rp_ua = get_rp_based_dcp_current(chg, typec_mode); vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua); } +#endif static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) { @@ -3978,8 +4648,10 @@ static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) return; typec_mode = smblib_get_prop_typec_mode(chg); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) if (chg->typec_present && (typec_mode != chg->typec_mode)) smblib_handle_rp_change(chg, typec_mode); +#endif chg->typec_mode = typec_mode; @@ -4143,18 +4815,39 @@ irqreturn_t smblib_handle_wdog_bark(int irq, void *data) struct smb_charger *chg = irq_data->parent_data; int rc; - smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); - rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT); if (rc < 0) smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc); - if (chg->step_chg_enabled || chg->sw_jeita_enabled) - power_supply_changed(chg->batt_psy); + return IRQ_HANDLED; +} + +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +irqreturn_t smblib_handle_aicl_done(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + u8 stat; + int rc; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + rc = smblib_read(chg, AICL_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc); + return IRQ_HANDLED; + } + + if (stat & ICL_IMIN_BIT) { + smblib_dbg(chg, PR_SOMC, + "ICL_IMIN is detected, suspending usbin\n"); + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 0); + } return IRQ_HANDLED; } +#endif /************** * Additional USB PSY getters/setters * that call interrupt functions @@ -4234,6 +4927,22 @@ static void bms_update_work(struct work_struct *work) power_supply_changed(chg->batt_psy); } +static void step_soc_req_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + step_soc_req_work.work); + union power_supply_propval pval = {0, }; + int rc; + + rc = smblib_get_prop_batt_capacity(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc); + return; + } + + step_charge_soc_update(chg, pval.intval); +} + static void clear_hdc_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, @@ -4395,13 +5104,17 @@ static void smblib_otg_oc_work(struct work_struct *work) goto unlock; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + somc_usb_otg_regulator_ocp_notify(chg); +#endif +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1); rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev); if (rc < 0) { smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc); goto unlock; } - +#endif unlock: mutex_unlock(&chg->otg_oc_lock); } @@ -4524,9 +5237,24 @@ static void smblib_legacy_detection_work(struct work_struct *work) legacy_detection_work); int rc; u8 stat; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) bool legacy, rp_high; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + bool legacy, rp_default; + union power_supply_propval val; +#endif +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) mutex_lock(&chg->lock); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + mutex_lock(&chg->legacy_detection_lock); + rc = smblib_get_prop_batt_status(chg, &val); + if (rc < 0) + val.intval = POWER_SUPPLY_STATUS_CHARGING; + chg->status_before_typec_en_dis_active = val.intval; +#endif chg->typec_en_dis_active = 1; smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n"); rc = smblib_masked_write(chg, @@ -4537,7 +5265,12 @@ static void smblib_legacy_detection_work(struct work_struct *work) smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc); /* wait for the adapter to turn off VBUS */ +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) msleep(500); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + msleep(400); +#endif rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, @@ -4546,7 +5279,12 @@ static void smblib_legacy_detection_work(struct work_struct *work) smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc); /* wait for type-c detection to complete */ +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) msleep(100); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + msleep(200); +#endif rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat); if (rc < 0) { @@ -4555,19 +5293,291 @@ static void smblib_legacy_detection_work(struct work_struct *work) } chg->typec_legacy_valid = true; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); +#endif legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH; if (!legacy || !rp_high) vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, false, 0); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) + val.intval = 0; + rp_default = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; + if (val.intval && (!legacy || rp_default)) + vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, + false, 0); +#endif unlock: chg->typec_en_dis_active = 0; smblib_usb_typec_change(chg); +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) mutex_unlock(&chg->lock); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + mutex_unlock(&chg->legacy_detection_lock); +#endif +} + +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +static void smblib_somc_fake_charging_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + fake_charging_work); + chg->duration_fake_charging = true; + msleep(500); + chg->duration_fake_charging = false; } +#define FV_JEITA_WARM_UV 4200000 +#define FV_JEITA_WARM_RB_WA_ENTER_UV 4200000 +#define FV_JEITA_WARM_RB_WA_EXIT_UV 4000000 +#define JEITA_WORK_DELAY_RETRY_MS 500 +#define JEITA_WORK_DELAY_CHARGING_MS 5000 +#define JEITA_WORK_DELAY_DISCHARGING_MS 30000 +#define JEITA_FAKE_CARGING_TIME_MS 500 +static void smblib_somc_jeita_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + jeita_work.work); + union power_supply_propval pval = {0, }; + int rc; + int batt_temp, skin_temp; + u8 reg; + u8 chg_stat; + bool vbus_rising; + bool skin_temp_failed = false; + int interval_ms; + int synth_cond; + int vbatt; + + if (!chg->jeita_sw_ctl_en) + return; + + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, ®); + if (rc < 0) { + dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); + return; + } + vbus_rising = (bool)(reg & USBIN_PLUGIN_RT_STS_BIT); + + rc = smblib_get_prop_batt_temp(chg, &pval); + if (rc < 0) + smblib_err(chg, "Couldn't get batt temp rc=%d\n", rc); + + batt_temp = pval.intval; + + rc = smblib_get_prop_batt_voltage_now(chg, &pval); + if (rc < 0) { + dev_err(chg->dev, "Couldn't read VBATT rc=%d\n", rc); + goto reschedule; + } + vbatt = pval.intval; + + if (chg->jeita_use_aux) { + rc = smblib_get_prop_skin_temp(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get skin temp rc=%d\n", rc); + skin_temp_failed = true; + } + skin_temp = pval.intval; + + smblib_dbg(chg, PR_MISC, + "vbus_rising=%d batt_temp=%d sikn_temp=%d\n", + (int)vbus_rising, batt_temp, + skin_temp_failed ? 0 : skin_temp); + } + + if (!chg->jeita_use_aux) { + chg->jeita_skin_temp_condition = TEMP_CONDITION_DEFAULT; + } else if (!skin_temp_failed) { + if (skin_temp > chg->jeita_aux_thresh_hot) + chg->jeita_skin_temp_condition = TEMP_CONDITION_HOT; + else if (skin_temp > chg->jeita_aux_thresh_warm) + chg->jeita_skin_temp_condition = TEMP_CONDITION_WARM; + else + chg->jeita_skin_temp_condition = TEMP_CONDITION_NORMAL; + } + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &chg_stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read charger status 1 rc=%d\n", rc); + return; + } + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, ®); + if (rc < 0) { + smblib_err(chg, "Couldn't read charger status 2 rc=%d\n", rc); + return; + } + if (reg & BAT_TEMP_STATUS_TOO_COLD_BIT) + chg->jeita_batt_temp_condition = TEMP_CONDITION_COLD; + else if (reg & BAT_TEMP_STATUS_TOO_HOT_BIT) + chg->jeita_batt_temp_condition = TEMP_CONDITION_HOT; + else if (reg & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT) + chg->jeita_batt_temp_condition = TEMP_CONDITION_COOL; + else if (reg & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT) + chg->jeita_batt_temp_condition = TEMP_CONDITION_WARM; + else + chg->jeita_batt_temp_condition = TEMP_CONDITION_NORMAL; + + switch (chg->jeita_batt_temp_condition) { + case TEMP_CONDITION_HOT: + synth_cond = TEMP_CONDITION_HOT; + break; + case TEMP_CONDITION_WARM: + if (chg->jeita_skin_temp_condition == TEMP_CONDITION_HOT) + synth_cond = TEMP_CONDITION_HOT; + else + synth_cond = TEMP_CONDITION_WARM; + break; + case TEMP_CONDITION_NORMAL: + if (chg->jeita_skin_temp_condition == TEMP_CONDITION_HOT) + synth_cond = TEMP_CONDITION_HOT; + else if (chg->jeita_skin_temp_condition == TEMP_CONDITION_WARM) + synth_cond = TEMP_CONDITION_WARM; + else + synth_cond = TEMP_CONDITION_NORMAL; + break; + case TEMP_CONDITION_COOL: + synth_cond = TEMP_CONDITION_COOL; + break; + case TEMP_CONDITION_COLD: + synth_cond = TEMP_CONDITION_COLD; + break; + default: + synth_cond = TEMP_CONDITION_NORMAL; + break; + } + smblib_dbg(chg, PR_MISC, "batt=%d skin=%d result=%d\n", + chg->jeita_batt_temp_condition, + chg->jeita_skin_temp_condition, + synth_cond); + + if (synth_cond == TEMP_CONDITION_HOT || + synth_cond == TEMP_CONDITION_COLD) + vote(chg->chg_disable_votable, JEITA_VOTER, true, 0); + else + vote(chg->chg_disable_votable, JEITA_VOTER, false, 0); + + if (synth_cond == TEMP_CONDITION_WARM) + vote(chg->fv_votable, JEITA_VOTER, true, FV_JEITA_WARM_UV); + else + vote(chg->fv_votable, JEITA_VOTER, false, 0); + + if (synth_cond == TEMP_CONDITION_WARM && chg->jeita_warm_fcc_ua > 0) + vote(chg->fcc_votable, JEITA_VOTER, true, + chg->jeita_warm_fcc_ua); + else if (synth_cond == TEMP_CONDITION_COOL && + chg->jeita_cool_fcc_ua > 0) + vote(chg->fcc_votable, JEITA_VOTER, true, + chg->jeita_cool_fcc_ua); + else + vote(chg->fcc_votable, JEITA_VOTER, false, 0); + + if (synth_cond != TEMP_CONDITION_NORMAL) { + power_supply_changed(chg->batt_psy); + smblib_dbg(chg, PR_SOMC, + "JEITA: batt_temp=%d(%d) skin_temp=%d(%d) result:%d\n", + batt_temp, chg->jeita_batt_temp_condition, + skin_temp, chg->jeita_skin_temp_condition, + synth_cond); + } + + /* WA for Reverse Boost */ + if (!chg->jeita_rb_warm_hi_vbatt_en && + vbus_rising && synth_cond == TEMP_CONDITION_WARM && + vbatt > FV_JEITA_WARM_RB_WA_ENTER_UV) { + smblib_dbg(chg, PR_SOMC, + "WA for RB after Warm. vbatt=%d\n", + vbatt); + chg->jeita_rb_warm_hi_vbatt_en = true; + vote(chg->usb_icl_votable, JEITA_VOTER, true, 0); + } else if (chg->jeita_rb_warm_hi_vbatt_en && + (!vbus_rising || synth_cond != TEMP_CONDITION_WARM || + vbatt < FV_JEITA_WARM_RB_WA_EXIT_UV)) { + smblib_dbg(chg, PR_SOMC, + "Release WA for RB after Warm. vbatt=%d\n", + vbatt); + vote(chg->usb_icl_votable, JEITA_VOTER, false, 0); + chg->jeita_rb_warm_hi_vbatt_en = false; + } + + /* WA for holding Charge Termination after normal */ + if (vbus_rising && + chg->jeita_synth_temp_condition == TEMP_CONDITION_WARM && + (synth_cond == TEMP_CONDITION_NORMAL || + synth_cond == TEMP_CONDITION_COOL) && + !get_effective_result(chg->chg_disable_votable) && + ((chg_stat & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE || + (chg_stat & BATTERY_CHARGER_STATUS_MASK) == INHIBIT_CHARGE || + (chg_stat & CC_SOFT_TERMINATE_BIT) == CC_SOFT_TERMINATE_BIT)) { + smblib_dbg(chg, PR_SOMC, "Execute WA for holding FULL\n"); + chg->jeita_keep_fake_charging = true; + vote(chg->chg_disable_votable, JEITA_VOTER, true, 0); + vote(chg->chg_disable_votable, JEITA_VOTER, false, 0); + msleep(JEITA_FAKE_CARGING_TIME_MS); + + smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, ®); + smblib_dbg(chg, PR_SOMC, "waiting done chg_sts1=0x%02x\n", reg); + chg->jeita_keep_fake_charging = false; + } + + chg->jeita_synth_temp_condition = synth_cond; + +reschedule: + if (vbus_rising && skin_temp_failed) + interval_ms = JEITA_WORK_DELAY_RETRY_MS; + else if (vbus_rising && !skin_temp_failed) + interval_ms = JEITA_WORK_DELAY_CHARGING_MS; + else + interval_ms = JEITA_WORK_DELAY_DISCHARGING_MS; + + smblib_dbg(chg, PR_MISC, "will schedule delayed worker (%d ms)\n", + interval_ms); + + if (chg->jeita_sw_ctl_en) + schedule_delayed_work(&chg->jeita_work, + msecs_to_jiffies(interval_ms)); +} + +static void smblib_somc_smart_charge_wdog_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + smart_charge_wdog_work.work); + + smblib_dbg(chg, PR_SOMC, "Smart Charge Watchdog timer has expired.\n"); + + mutex_lock(&chg->smart_charge_lock); + vote(chg->chg_disable_votable, BATTCHG_SMART_EN_VOTER, false, 0); + chg->smart_charge_suspended = false; + mutex_unlock(&chg->smart_charge_lock); + + power_supply_changed(chg->batt_psy); +} + +static void smblib_somc_removal_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + usb_removal_work.work); + + if (chg->usb_removal_input && !chg->low_batt_shutdown_enabled) { + /* key event for power off charge */ + smblib_dbg(chg, PR_SOMC, "input_report_key KEY_F24\n"); + input_report_key(chg->usb_removal_input, KEY_F24, 1); + input_sync(chg->usb_removal_input); + input_report_key(chg->usb_removal_input, KEY_F24, 0); + input_sync(chg->usb_removal_input); + } +} + +#endif + static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; @@ -4763,9 +5773,19 @@ int smblib_init(struct smb_charger *chg) mutex_init(&chg->write_lock); mutex_init(&chg->otg_oc_lock); mutex_init(&chg->vconn_oc_lock); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + mutex_init(&chg->smart_charge_lock); + mutex_init(&chg->thermal_lock); + mutex_init(&chg->xo_lock); + mutex_init(&chg->legacy_detection_lock); + wake_lock_init(&chg->usb_removal_wakelock.lock, + WAKE_LOCK_SUSPEND, "unplug_wakelock"); + chg->usb_removal_wakelock.enabled = true; +#endif INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); + INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work); INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work); INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work); INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work); @@ -4775,6 +5795,33 @@ int smblib_init(struct smb_charger *chg) INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work); INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work); INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + INIT_WORK(&chg->fake_charging_work, smblib_somc_fake_charging_work); + INIT_DELAYED_WORK(&chg->smart_charge_wdog_work, + smblib_somc_smart_charge_wdog_work); + INIT_DELAYED_WORK(&chg->usb_removal_work, smblib_somc_removal_work); + INIT_DELAYED_WORK(&chg->jeita_work, smblib_somc_jeita_work); + + /* register input device */ + chg->usb_removal_input = input_allocate_device(); + if (!chg->usb_removal_input) { + dev_err(chg->dev, + "can't allocate unplug virtual button\n"); + rc = -ENOMEM; + return rc; + } + input_set_capability(chg->usb_removal_input, EV_KEY, KEY_F24); + chg->usb_removal_input->name = "SOMC USB Removal"; + chg->usb_removal_input->dev.parent = chg->dev; + + rc = input_register_device(chg->usb_removal_input); + if (rc) { + dev_err(chg->dev, + "can't register power key: %d\n", rc); + rc = -ENOMEM; + return rc; + } +#endif chg->fake_capacity = -EINVAL; chg->fake_input_current_limited = -EINVAL; @@ -4787,14 +5834,6 @@ int smblib_init(struct smb_charger *chg) return rc; } - rc = qcom_step_chg_init(chg->step_chg_enabled, - chg->sw_jeita_enabled); - if (rc < 0) { - smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n", - rc); - return rc; - } - rc = smblib_create_votables(chg); if (rc < 0) { smblib_err(chg, "Couldn't create votables rc=%d\n", @@ -4829,6 +5868,7 @@ int smblib_deinit(struct smb_charger *chg) cancel_work_sync(&chg->bms_update_work); cancel_work_sync(&chg->rdstd_cc2_detach_work); cancel_delayed_work_sync(&chg->hvdcp_detect_work); + cancel_delayed_work_sync(&chg->step_soc_req_work); cancel_delayed_work_sync(&chg->clear_hdc_work); cancel_work_sync(&chg->otg_oc_work); cancel_work_sync(&chg->vconn_oc_work); @@ -4840,7 +5880,6 @@ int smblib_deinit(struct smb_charger *chg) cancel_delayed_work_sync(&chg->bb_removal_work); power_supply_unreg_notifier(&chg->nb); smblib_destroy_votables(chg); - qcom_step_chg_deinit(); qcom_batt_deinit(); break; case PARALLEL_SLAVE: @@ -4850,7 +5889,323 @@ int smblib_deinit(struct smb_charger *chg) return -EINVAL; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + if (!IS_ERR(chg->xo_clk)) + clk_put(chg->xo_clk); + + if (chg->usb_removal_input) { + input_free_device(chg->usb_removal_input); + chg->usb_removal_input = NULL; + } + if (chg->usb_removal_wakelock.enabled) { + wake_lock_destroy(&chg->usb_removal_wakelock.lock); + chg->usb_removal_wakelock.enabled = false; + } +#endif smblib_iio_deinit(chg); return 0; } + +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + +/************************** + * SOMC feature functions * + **************************/ + +void smblib_somc_thermal_fcc_change(struct smb_charger *chg) +{ + int lv = chg->system_temp_level; + + smblib_dbg(chg, PR_MISC, "thermal fcc change lv=%d\n", lv); + + if (IS_ERR_OR_NULL(chg->thermal_fcc_ua)) { + smblib_dbg(chg, PR_MISC, "thermal fcc table is NULL\n"); + return; + } + + if (lv > chg->thermal_fcc_levels - 1) { + smblib_dbg(chg, PR_MISC, "thermal lv is out of range\n"); + return; + } + + if (chg->thermal_fcc_ua[lv] > 0) { + vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true, + chg->thermal_fcc_ua[lv]); + vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0); + } else { + vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, true, 0); + vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0); + } +} + +void smblib_somc_thermal_icl_change(struct smb_charger *chg) +{ + int rc; + u8 stat; + int pulses; + int icl = 0; + int lv = chg->system_temp_level; + int type; + + mutex_lock(&chg->thermal_lock); + smblib_dbg(chg, PR_MISC, "thermal icl change lv=%d\n", lv); + + if (IS_ERR_OR_NULL(chg->thermal_lo_volt_icl_ua) || + IS_ERR_OR_NULL(chg->thermal_hi_volt_icl_ua)) { + smblib_dbg(chg, PR_MISC, "thermal icl table is NULL\n"); + goto unlock; + } + + if (lv > chg->thermal_lo_volt_icl_levels - 1 || + lv > chg->thermal_hi_volt_icl_levels - 1) { + smblib_dbg(chg, PR_MISC, "thermal lv is out of range\n"); + goto unlock; + } + + if (chg->thermal_lo_volt_icl_levels != + chg->thermal_hi_volt_icl_levels) { + smblib_dbg(chg, PR_MISC, "thermal table size missmatch\n"); + goto unlock; + } + + type = chg->real_charger_type; + if (type == POWER_SUPPLY_TYPE_USB_HVDCP) { + rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, + "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc); + goto unlock; + } + + switch (stat & QC_2P0_STATUS_MASK) { + case QC_5V_BIT: + icl = chg->thermal_lo_volt_icl_ua[lv]; + break; + case QC_9V_BIT: + case QC_12V_BIT: + icl = chg->thermal_hi_volt_icl_ua[lv]; + break; + default: + icl = chg->thermal_lo_volt_icl_ua[lv]; + break; + } + smblib_dbg(chg, PR_MISC, "QC2.0: icl=%duA\n", icl); + } else if (type == POWER_SUPPLY_TYPE_USB_HVDCP_3) { + rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, + "Couldn't read QC_PULSE_COUNT rc=%d\n", rc); + goto unlock; + } + pulses = (stat & QC_PULSE_COUNT_MASK); + + if (pulses >= QC3_PULSES_FOR_6V) + icl = chg->thermal_hi_volt_icl_ua[lv]; + else + icl = chg->thermal_lo_volt_icl_ua[lv]; + + smblib_dbg(chg, PR_MISC, "QC3.0: icl=%duA\n", icl); + } else if (type == POWER_SUPPLY_TYPE_USB_PD) { + if (chg->voltage_max_uv >= 6000000) + icl = chg->thermal_hi_volt_icl_ua[lv]; + else + icl = chg->thermal_lo_volt_icl_ua[lv]; + + smblib_dbg(chg, PR_MISC, "PD: icl=%duA\n", icl); + } else if (type == POWER_SUPPLY_TYPE_USB) { + if (chg->thermal_lo_volt_icl_ua[lv] == 0) + icl = 0; + else if (chg->thermal_lo_volt_icl_ua[lv] < USBIN_150MA) + icl = USBIN_100MA; + else if (chg->thermal_lo_volt_icl_ua[lv] < USBIN_500MA) + icl = USBIN_150MA; + else if (chg->thermal_lo_volt_icl_ua[lv] < USBIN_900MA) + icl = USBIN_500MA; + else + icl = USBIN_900MA; + + if (chg->thermal_lo_volt_icl_ua[lv] != icl) + smblib_dbg(chg, PR_MISC, "Round icl for SDP %d to %d\n", + chg->thermal_lo_volt_icl_ua[lv], icl); + + smblib_dbg(chg, PR_MISC, "SDP: icl=%duA\n", icl); + } else { + icl = chg->thermal_lo_volt_icl_ua[lv]; + smblib_dbg(chg, PR_MISC, "DCP/Other: icl=%duA\n", icl); + } + + vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true, icl); +unlock: + mutex_unlock(&chg->thermal_lock); + return; +} + +void smblib_somc_set_low_batt_suspend_en(struct smb_charger *chg) +{ + int rc; + + rc = vote(chg->usb_icl_votable, LOW_BATT_EN_VOTER, true, 0); + if (rc < 0) + dev_err(chg->dev, "Couldn't set usb suspend rc %d\n", rc); + + rc = vote(chg->dc_suspend_votable, LOW_BATT_EN_VOTER, true, 0); + if (rc < 0) + dev_err(chg->dev, "Couldn't set dc suspend rc %d\n", rc); +} + +#define FULL_CAPACITY 100 +#define DECIMAL_CEIL 100 + +int smblib_somc_lrc_get_capacity(struct smb_charger *chg, int capacity) +{ + int ceil, magni; + + if (chg->lrc_fake_capacity && + chg->lrc_enabled && chg->lrc_socmax) { + magni = FULL_CAPACITY * DECIMAL_CEIL / chg->lrc_socmax; + capacity *= magni; + ceil = (capacity % DECIMAL_CEIL) ? 1 : 0; + capacity = capacity / DECIMAL_CEIL + ceil; + if (capacity > FULL_CAPACITY) + capacity = FULL_CAPACITY; + } + return capacity; +} + +void smblib_somc_lrc_vote(struct smb_charger *chg, enum somc_lrc_status status) +{ + int rc; + + if (status == LRC_CHG_OFF) + rc = vote(chg->chg_disable_votable, BATTCHG_LRC_EN_VOTER, + true, 0); + else + rc = vote(chg->chg_disable_votable, BATTCHG_LRC_EN_VOTER, + false, 0); + + if (rc < 0) + dev_err(chg->dev, + "Couldn't vote for battchg suspend: rc = %d\n", rc); +} + +void smblib_somc_lrc_check(struct smb_charger *chg) +{ + int rc, soc = 0; + enum somc_lrc_status retcode = LRC_DISABLE; + union power_supply_propval val = {0, }; + + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0 || !val.intval) + goto exit; + + if (chg->lrc_enabled) { + if (chg->lrc_socmax <= chg->lrc_socmin) { + pr_err("invalid SOC min:%d max:%d\n", chg->lrc_socmin, + chg->lrc_socmax); + goto exit; + } + } else { + if (chg->lrc_status == LRC_CHG_OFF) + smblib_somc_lrc_vote(chg, LRC_CHG_ON); + goto exit; + } + + if (chg->bms_psy) { + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_CAPACITY, &val); + if (rc) { + pr_err("Couldn't get soc rc = %d\n", rc); + goto exit; + } else { + soc = val.intval; + } + } + + if (soc >= (chg->lrc_socmax + chg->lrc_hysterisis)) + retcode = LRC_CHG_OFF; + else if (soc <= chg->lrc_socmin) + retcode = LRC_CHG_ON; + else if (chg->lrc_status == LRC_CHG_OFF) + retcode = LRC_CHG_OFF; + else + retcode = LRC_CHG_ON; + + if (retcode != chg->lrc_status) + smblib_somc_lrc_vote(chg, retcode); + + chg->lrc_status = retcode; + + if (chg->lrc_fake_capacity && soc > chg->lrc_socmax) + vote(chg->usb_icl_votable, LRC_OVER_SOC_EN_VOTER, true, 0); + else + vote(chg->usb_icl_votable, LRC_OVER_SOC_EN_VOTER, false, 0); + return; + +exit: + chg->lrc_status = LRC_DISABLE; + return; +} + +#define SMART_CHARGE_WDOG_DELAY_MS (30 * 60 * 1000) /* 30min */ + +int smblib_somc_smart_set_suspend(struct smb_charger *chg) +{ + int rc = 0; + + if (!chg->smart_charge_enabled) { + pr_err("Couldn't set smart charge voter due to unactivated\n"); + goto exit; + } + + rc = vote(chg->chg_disable_votable, BATTCHG_SMART_EN_VOTER, + chg->smart_charge_suspended, 0); + if (rc < 0) { + pr_err("Couldn't vote en rc %d\n", rc); + goto exit; + } + + smblib_dbg(chg, PR_SOMC, "voted for smart charging (%d).\n", + chg->smart_charge_suspended); + cancel_delayed_work_sync(&chg->smart_charge_wdog_work); + if (chg->smart_charge_suspended) { + schedule_delayed_work(&chg->smart_charge_wdog_work, + msecs_to_jiffies(SMART_CHARGE_WDOG_DELAY_MS)); + } +exit: + return rc; +} + +int smblib_get_usb_max_current_limited(struct smb_charger *chg) +{ + int rc; + u8 reg; + rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, ®); + if (rc < 0) { + smblib_err(chg, "Couldn't read USBIN_ICL_OPTIONS_REG rc=%d\n", rc); + return 0; + } + + reg &= (CFG_USB3P0_SEL_BIT | USB51_MODE_BIT); + + switch (reg) { + case 0: + rc = USBIN_100MA / 1000; + break; + case CFG_USB3P0_SEL_BIT: + rc = USBIN_150MA / 1000; + break; + case USB51_MODE_BIT: + rc = USBIN_500MA / 1000; + break; + case (CFG_USB3P0_SEL_BIT | USB51_MODE_BIT): + rc = USBIN_900MA / 1000; + break; + default: + rc = 0; + break; + } + return rc; +} + +#endif diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index a89d09711ec8ccaaa28695790a2764606e0383ff..0fca1a4646abdc7f83a53d57a4f3d063c6241b97 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __SMB2_CHARGER_H #define __SMB2_CHARGER_H @@ -18,6 +23,10 @@ #include #include #include +#include +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#include +#endif #include "storm-watch.h" enum print_reason { @@ -26,6 +35,9 @@ enum print_reason { PR_MISC = BIT(2), PR_PARALLEL = BIT(3), PR_OTG = BIT(4), +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + PR_SOMC = BIT(15), +#endif }; #define DEFAULT_VOTER "DEFAULT_VOTER" @@ -35,6 +47,13 @@ enum print_reason { #define QC_VOTER "QC_VOTER" #define PL_USBIN_USBIN_VOTER "PL_USBIN_USBIN_VOTER" #define USB_PSY_VOTER "USB_PSY_VOTER" +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define BATTCHG_SMART_EN_VOTER "BATTCHG_SMART_EN_VOTER" +#define BATTCHG_LRC_EN_VOTER "BATTCHG_LRC_EN_VOTER" +#define LRC_OVER_SOC_EN_VOTER "LRC_OVER_SOC_EN_VOTER" +#define PRODUCT_VOTER "PRODUCT_VOTER" +#define HIGH_VOLTAGE_VOTER "HIGH_VOLTAGE_VOTER" +#endif #define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER" #define PL_QNOVO_VOTER "PL_QNOVO_VOTER" #define USBIN_V_VOTER "USBIN_V_VOTER" @@ -70,7 +89,11 @@ enum print_reason { #define OTG_MAX_ATTEMPTS 3 #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 - +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define JEITA_VOTER "JEITA_VOTER" +#define LOW_BATT_EN_VOTER "LOW_BATT_EN_VOTER" +#define QNS_VOTER "QNS_VOTER" +#endif enum smb_mode { PARALLEL_MASTER = 0, PARALLEL_SLAVE, @@ -139,14 +162,17 @@ struct smb_irq_info { static const unsigned int smblib_extcon_cable[] = { EXTCON_USB, EXTCON_USB_HOST, - EXTCON_USB_CC, - EXTCON_USB_SPEED, EXTCON_NONE, }; -/* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */ -static const u32 smblib_extcon_exclusive[] = {0x3, 0}; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +enum somc_lrc_status { + LRC_DISABLE, + LRC_CHG_OFF, + LRC_CHG_ON, +}; +#endif struct smb_regulator { struct regulator_dev *rdev; struct regulator_desc rdesc; @@ -181,6 +207,18 @@ struct smb_chg_freq { unsigned int freq_above_otg_threshold; }; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +struct somc_usb_ocp { + struct regulator_ocp_notification notification; + spinlock_t lock; +}; + +struct usb_somc_params { + struct somc_usb_ocp ocp; + u8 apsd_result_bit; +}; + +#endif struct smb_params { struct smb_chg_param fcc; struct smb_chg_param fv; @@ -195,6 +233,9 @@ struct smb_params { struct smb_chg_param dc_icl_div2_mid_hv; struct smb_chg_param dc_icl_div2_hv; struct smb_chg_param jeita_cc_comp; + struct smb_chg_param step_soc_threshold[4]; + struct smb_chg_param step_soc; + struct smb_chg_param step_cc_delta[5]; struct smb_chg_param freq_buck; struct smb_chg_param freq_boost; }; @@ -213,6 +254,9 @@ struct smb_iio { struct iio_channel *connector_temp_thr1_chan; struct iio_channel *connector_temp_thr2_chan; struct iio_channel *connector_temp_thr3_chan; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + struct iio_channel *skin_temp_chan; +#endif }; struct reg_info { @@ -223,6 +267,13 @@ struct reg_info { const char *desc; }; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +struct somc_wake_lock { + struct wake_lock lock; + bool enabled; +}; + +#endif struct smb_charger { struct device *dev; char *name; @@ -243,6 +294,11 @@ struct smb_charger { struct mutex ps_change_lock; struct mutex otg_oc_lock; struct mutex vconn_oc_lock; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + struct mutex thermal_lock; + struct mutex xo_lock; + struct mutex legacy_detection_lock; +#endif /* power supplies */ struct power_supply *batt_psy; @@ -265,6 +321,12 @@ struct smb_charger { struct smb_regulator *vconn_vreg; struct regulator *dpdm_reg; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + /* clocks */ + struct clk *xo_clk; + bool xo_holded; + +#endif /* votables */ struct votable *dc_suspend_votable; struct votable *fcc_votable; @@ -289,6 +351,7 @@ struct smb_charger { struct work_struct rdstd_cc2_detach_work; struct delayed_work hvdcp_detect_work; struct delayed_work ps_change_timeout_work; + struct delayed_work step_soc_req_work; struct delayed_work clear_hdc_work; struct work_struct otg_oc_work; struct work_struct vconn_oc_work; @@ -306,15 +369,29 @@ struct smb_charger { bool system_suspend_supported; int boost_threshold_ua; int system_temp_level; +#if !defined(CONFIG_SOMC_CHARGER_EXTENSION) int thermal_levels; int *thermal_mitigation; +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int *thermal_fcc_ua; + int *thermal_lo_volt_icl_ua; + int *thermal_hi_volt_icl_ua; + int thermal_fcc_levels; + int thermal_lo_volt_icl_levels; + int thermal_hi_volt_icl_levels; +#endif int dcp_icl_ua; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int product_icl_ua; + int high_voltage_icl_ua; +#endif int fake_capacity; bool step_chg_enabled; - bool sw_jeita_enabled; bool is_hdc; bool chg_done; bool micro_usb_mode; + int input_limited_fcc_ua; bool otg_en; bool vconn_en; bool suspend_input_on_debug_batt; @@ -330,16 +407,14 @@ struct smb_charger { int fake_input_current_limited; bool pr_swap_in_progress; int typec_mode; - int usb_icl_change_irq_enabled; - u32 jeita_status; - u8 float_cfg; - bool use_extcon; - bool otg_present; /* workaround flag */ u32 wa_flags; bool cc2_detach_wa_active; bool typec_en_dis_active; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + int status_before_typec_en_dis_active; +#endif int boost_current_ua; int temp_speed_reading_count; @@ -353,6 +428,55 @@ struct smb_charger { /* qnovo */ int usb_icl_delta_ua; int pulse_cnt; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + struct usb_somc_params usb_params; + int usb_switch_sel_gpio; + + bool duration_fake_charging; + struct work_struct fake_charging_work; + + /* jeita */ + struct delayed_work jeita_work; + bool jeita_sw_ctl_en; + bool jeita_use_aux; + int jeita_skin_temp_condition; + int jeita_batt_temp_condition; + int jeita_synth_temp_condition; + int jeita_aux_thresh_hot; + int jeita_aux_thresh_warm; + int jeita_warm_fcc_ua; + int jeita_cool_fcc_ua; + bool jeita_vbus_rising; + bool jeita_rb_warm_hi_vbatt_en; + bool jeita_keep_fake_charging; + + /* low batt shutdown */ + int low_batt_shutdown_enabled; + + /* smart charge */ + bool smart_charge_enabled; + bool smart_charge_suspended; + struct delayed_work smart_charge_wdog_work; + struct mutex smart_charge_lock; + + /* limited range charge */ + bool lrc_enabled; + int lrc_socmax; + int lrc_socmin; + int lrc_status; + bool lrc_fake_capacity; + int lrc_hysterisis; + + /* usb remove */ + struct delayed_work usb_removal_work; + struct input_dev *usb_removal_input; + struct somc_wake_lock usb_removal_wakelock; + + /* misc */ + bool int_cld; + int faked_status; + +#endif }; int smblib_read(struct smb_charger *chg, u16 addr, u8 *val); @@ -364,6 +488,9 @@ int smblib_get_charge_param(struct smb_charger *chg, int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend); int smblib_enable_charging(struct smb_charger *chg, bool enable); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +const char *smblib_somc_get_charger_type(struct smb_charger *chg); +#endif int smblib_set_charge_param(struct smb_charger *chg, struct smb_chg_param *param, int val_u); int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend); @@ -377,11 +504,19 @@ int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param, int val_u, u8 *val_raw); int smblib_set_chg_freq(struct smb_chg_param *param, int val_u, u8 *val_raw); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +int somc_usb_register(struct smb_charger *chg); +void somc_usb_unregister(struct smb_charger *chg); +#endif int smblib_vbus_regulator_enable(struct regulator_dev *rdev); int smblib_vbus_regulator_disable(struct regulator_dev *rdev); int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev); - +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +int somc_usb_otg_regulator_register_ocp_notification( + struct regulator_dev *rdev, + struct regulator_ocp_notification *notification); +#endif int smblib_vconn_regulator_enable(struct regulator_dev *rdev); int smblib_vconn_regulator_disable(struct regulator_dev *rdev); int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev); @@ -389,6 +524,9 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev); irqreturn_t smblib_handle_debug(int irq, void *data); irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data); irqreturn_t smblib_handle_chg_state_change(int irq, void *data); +irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data); +irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data); +irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data); irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data); irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data); irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data); @@ -401,7 +539,18 @@ irqreturn_t smblib_handle_dc_plugin(int irq, void *data); irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data); irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data); irqreturn_t smblib_handle_wdog_bark(int irq, void *data); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +irqreturn_t smblib_handle_aicl_done(int irq, void *data); +#endif +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +int smblib_get_prop_charging_enabled(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_prop_charge_full_design(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_prop_charge_full(struct smb_charger *chg, + union power_supply_propval *val); +#endif int smblib_get_prop_input_suspend(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_batt_present(struct smb_charger *chg, @@ -428,6 +577,13 @@ int smblib_get_prop_batt_temp(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_step_chg_step(struct smb_charger *chg, + union power_supply_propval *val); + +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +int smblib_set_prop_charging_enabled(struct smb_charger *chg, + const union power_supply_propval *val); +#endif int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_batt_capacity(struct smb_charger *chg, @@ -472,6 +628,10 @@ int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_pe_start(struct smb_charger *chg, union power_supply_propval *val); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +int smblib_get_prop_skin_temp(struct smb_charger *chg, + union power_supply_propval *val); +#endif int smblib_get_prop_charger_temp(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_charger_temp_max(struct smb_charger *chg, @@ -505,10 +665,9 @@ int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg, void smblib_suspend_on_debug_battery(struct smb_charger *chg); int smblib_rerun_apsd_if_required(struct smb_charger *chg); int smblib_get_prop_fcc_delta(struct smb_charger *chg, - union power_supply_propval *val); + union power_supply_propval *val); int smblib_icl_override(struct smb_charger *chg, bool override); int smblib_dp_dm(struct smb_charger *chg, int val); -int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable); int smblib_rerun_aicl(struct smb_charger *chg); int smblib_set_icl_current(struct smb_charger *chg, int icl_ua); int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua); @@ -518,6 +677,16 @@ int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, const union power_supply_propval *val); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +void smblib_somc_thermal_fcc_change(struct smb_charger *chg); +void smblib_somc_thermal_icl_change(struct smb_charger *chg); +void smblib_somc_set_low_batt_suspend_en(struct smb_charger *chg); +int smblib_somc_smart_set_suspend(struct smb_charger *chg); +int smblib_somc_lrc_get_capacity(struct smb_charger *chg, + int capacity); +void smblib_somc_lrc_check(struct smb_charger *chg); +int smblib_get_usb_max_current_limited(struct smb_charger *chg); +#endif int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); #endif /* __SMB2_CHARGER_H */ diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index d8671ab1fd06debcc4a50accc9812cf3d9d53c70..a47fb55b2da2d41e8a22fbb03f3f4230f588a861 100644 --- a/drivers/power/supply/qcom/smb-reg.h +++ b/drivers/power/supply/qcom/smb-reg.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __SMB2_CHARGER_REG_H #define __SMB2_CHARGER_REG_H @@ -108,6 +113,10 @@ enum { #define BAT_ID_BMISS_CMP_BIT BIT(1) #define THERM_CMP_BIT BIT(0) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define CHGR_INT_RT_STS_REG (CHGR_BASE + 0x10) + +#endif /* CHGR Interrupt Bits */ #define CHGR_7_RT_STS_BIT BIT(7) #define CHGR_6_RT_STS_BIT BIT(6) @@ -389,6 +398,10 @@ enum { #define BAT_OCP_RT_STS_BIT BIT(1) #define BAT_TEMP_RT_STS_BIT BIT(0) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define BATIF_INT_RT_STS_REG (BATIF_BASE + 0x10) + +#endif #define SHIP_MODE_REG (BATIF_BASE + 0x40) #define SHIP_MODE_EN_BIT BIT(0) @@ -525,6 +538,10 @@ enum { #define TYPEC_TRYSOURCE_DETECT_STATUS_BIT BIT(1) #define TYPEC_TRYSINK_DETECT_STATUS_BIT BIT(0) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define USB_INT_RT_STS_REG (USBIN_BASE + 0x10) + +#endif /* USBIN Interrupt Bits */ #define TYPE_C_CHANGE_RT_STS_BIT BIT(7) #define USBIN_ICL_CHANGE_RT_STS_BIT BIT(6) @@ -587,6 +604,18 @@ enum { #define EN_LEGACY_CABLE_DETECTION_BIT BIT(1) #define ALLOW_PD_DRING_UFP_TCCDB_BIT BIT(0) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define HVDCP_PULSE_COUNT_MAX_CFG_REG (USBIN_BASE + 0x5B) +#define HVDCP_PULSE_COUNT_MAX_QC3P0 GENMASK(5, 0) +#define HVDCP_PULSE_COUNT_MAX_QC2P0 GENMASK(7, 6) +#define QC3P0_MAX_PULSE_5V 0 +#define QC3P0_MAX_PULSE_9V 20 +#define QC3P0_MAX_PULSE_12V 35 +#define QC2P0_MAX_PULSE_5V 0 +#define QC2P0_MAX_PULSE_9V BIT(6) +#define QC2P0_MAX_PULSE_12V BIT(7) + +#endif #define USBIN_ADAPTER_ALLOW_CFG_REG (USBIN_BASE + 0x60) #define USBIN_ADAPTER_ALLOW_MASK GENMASK(3, 0) enum { @@ -629,6 +658,14 @@ enum { #define USBIN_LOAD_CFG_REG (USBIN_BASE + 0x65) #define USBIN_OV_CH_LOAD_OPTION_BIT BIT(7) #define ICL_OVERRIDE_AFTER_APSD_BIT BIT(4) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define AICL_USE_SW_AFTER_APSD BIT(4) +#define USBIN_IN_COLLAPSE_GF_SEL GENMASK(1, 0) +#define USBIN_IN_COLLAPSE_GF_1MS 0 +#define USBIN_IN_COLLAPSE_GF_5MS 1 +#define USBIN_IN_COLLAPSE_GF_30MS 2 +#define USBIN_IN_COLLAPSE_GF_30US 3 +#endif #define USBIN_ICL_OPTIONS_REG (USBIN_BASE + 0x66) #define CFG_USB3P0_SEL_BIT BIT(2) @@ -679,15 +716,27 @@ enum { #define USBIN_5V_AICL_THRESHOLD_CFG_REG (USBIN_BASE + 0x81) #define USBIN_5V_AICL_THRESHOLD_CFG_MASK GENMASK(2, 0) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define USBIN_5V_AICL_THRESHOLD_4P0V 0 +#define USBIN_5V_AICL_THRESHOLD_4P5V 5 +#endif #define USBIN_9V_AICL_THRESHOLD_CFG_REG (USBIN_BASE + 0x82) #define USBIN_9V_AICL_THRESHOLD_CFG_MASK GENMASK(2, 0) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define USBIN_9V_AICL_THRESHOLD_7P2V 0 +#define USBIN_9V_AICL_THRESHOLD_7P6V 2 +#endif #define USBIN_12V_AICL_THRESHOLD_CFG_REG (USBIN_BASE + 0x83) #define USBIN_12V_AICL_THRESHOLD_CFG_MASK GENMASK(2, 0) #define USBIN_CONT_AICL_THRESHOLD_CFG_REG (USBIN_BASE + 0x84) #define USBIN_CONT_AICL_THRESHOLD_CFG_MASK GENMASK(5, 0) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define USBIN_CONT_AICL_THRESHOLD_4P0V 0 +#define USBIN_CONT_AICL_THRESHOLD_4P5V 5 +#endif /* DCIN Peripheral Registers */ #define DCIN_INPUT_STATUS_REG (DCIN_BASE + 0x06) @@ -877,6 +926,10 @@ enum { #define SYSOK_REASON_DCIN_BIT BIT(1) #define SYSOK_REASON_USBIN_BIT BIT(0) +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define MISC_INT_RT_STS_REG (MISC_BASE + 0x10) + +#endif /* MISC Interrupt Bits */ #define SWITCHER_POWER_OK_RT_STS_BIT BIT(7) #define TEMPERATURE_CHANGE_RT_STS_BIT BIT(6) diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index e7ca1e3fb1082c3bcbc1d5d1154d6dd87af27fb9..c633245fe73ba663cc590829017abfbabf25b6a7 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -837,13 +837,6 @@ static int smb138x_init_slave_hw(struct smb138x *chip) } } - /* configure to a fixed 700khz freq to avoid tdie errors */ - rc = smblib_set_charge_param(chg, &chg->param.freq_buck, 700); - if (rc < 0) { - pr_err("Couldn't configure 700Khz switch freq rc=%d\n", rc); - return rc; - } - /* enable watchdog bark and bite interrupts, and disable the watchdog */ rc = smblib_masked_write(chg, WD_CFG_REG, WDOG_TIMER_EN_BIT | WDOG_TIMER_EN_ON_PLUGIN_BIT | BITE_WDOG_INT_EN_BIT @@ -863,13 +856,6 @@ static int smb138x_init_slave_hw(struct smb138x *chip) return rc; } - /* Disable OTG */ - rc = smblib_masked_write(chg, CMD_OTG_REG, OTG_EN_BIT, 0); - if (rc < 0) { - pr_err("Couldn't disable OTG rc=%d\n", rc); - return rc; - } - /* suspend parallel charging */ rc = smb138x_set_parallel_suspend(chip, true); if (rc < 0) { @@ -967,20 +953,6 @@ static int smb138x_init_hw(struct smb138x *chip) chg->dcp_icl_ua = chip->dt.usb_icl_ua; - /* Disable OTG */ - rc = smblib_masked_write(chg, CMD_OTG_REG, OTG_EN_BIT, 0); - if (rc < 0) { - pr_err("Couldn't disable OTG rc=%d\n", rc); - return rc; - } - - /* Unsuspend USB input */ - rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT, 0); - if (rc < 0) { - pr_err("Couldn't unsuspend USB, rc=%d\n", rc); - return rc; - } - /* configure to a fixed 700khz freq to avoid tdie errors */ rc = smblib_set_charge_param(chg, &chg->param.freq_buck, 700); if (rc < 0) { @@ -1621,33 +1593,14 @@ static int smb138x_remove(struct platform_device *pdev) return 0; } -static void smb138x_shutdown(struct platform_device *pdev) -{ - struct smb138x *chip = platform_get_drvdata(pdev); - struct smb_charger *chg = &chip->chg; - int rc; - - /* Suspend charging */ - rc = smb138x_set_parallel_suspend(chip, true); - if (rc < 0) - pr_err("Couldn't suspend charging rc=%d\n", rc); - - /* Disable OTG */ - rc = smblib_masked_write(chg, CMD_OTG_REG, OTG_EN_BIT, 0); - if (rc < 0) - pr_err("Couldn't disable OTG rc=%d\n", rc); - -} - static struct platform_driver smb138x_driver = { .driver = { .name = "qcom,smb138x-charger", .owner = THIS_MODULE, .of_match_table = match_table, }, - .probe = smb138x_probe, - .remove = smb138x_remove, - .shutdown = smb138x_shutdown, + .probe = smb138x_probe, + .remove = smb138x_remove, }; module_platform_driver(smb138x_driver); diff --git a/drivers/pwm/pwm-qpnp.c b/drivers/pwm/pwm-qpnp.c index 2531b74b4588d816fad242ff276c8ede2ef90a2d..c6fbb1ca20925318c7ad197c71a5649fafe18593 100644 --- a/drivers/pwm/pwm-qpnp.c +++ b/drivers/pwm/pwm-qpnp.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * Qualcomm Technologies, Inc. QPNP Pulse Width Modulation (PWM) driver * @@ -37,6 +42,9 @@ #define QPNP_LPG_CHAN_SUB_TYPE 0x2 #define QPNP_LPG_S_CHAN_SUB_TYPE 0x11 +/* LPG Control for LUT_RAMP_CONTROL */ +#define QPNP_LUT_RAMP_CONTROL_MASK 0xFF + /* LPG Control for LPG_PATTERN_CONFIG */ #define QPNP_RAMP_DIRECTION_SHIFT 4 #define QPNP_RAMP_DIRECTION_MASK 0x10 @@ -312,6 +320,7 @@ struct qpnp_lpg_config { struct _qpnp_pwm_config { int pwm_value; + int pwm_max_value; int pwm_period; /* in microseconds */ int pwm_duty; /* in microseconds */ struct pwm_period_config period; @@ -328,7 +337,6 @@ struct qpnp_pwm_chip { bool enabled; struct _qpnp_pwm_config pwm_config; struct qpnp_lpg_config lpg_config; - enum pm_pwm_mode pwm_mode; spinlock_t lpg_lock; enum qpnp_lpg_revision revision; u8 sub_type; @@ -586,6 +594,7 @@ static int qpnp_lpg_change_table(struct qpnp_pwm_chip *chip, { unsigned int pwm_value, max_pwm_value; struct qpnp_lut_config *lut = &chip->lpg_config.lut_config; + struct _qpnp_pwm_config *pwm_config = &chip->pwm_config; int i, pwm_size, rc = 0; int burst_size = SPMI_MAX_BUF_LEN; int list_len = lut->list_len << 1; @@ -596,6 +605,9 @@ static int qpnp_lpg_change_table(struct qpnp_pwm_chip *chip, QPNP_MIN_PWM_BIT_SIZE; max_pwm_value = (1 << pwm_size) - 1; + if (pwm_config->pwm_max_value + && (max_pwm_value > pwm_config->pwm_max_value)) + max_pwm_value = pwm_config->pwm_max_value; if (unlikely(lut->list_len != (lut->hi_index - lut->lo_index + 1))) { pr_err("LUT internal Data structure corruption detected\n"); @@ -693,6 +705,9 @@ static int qpnp_lpg_save_pwm_value(struct qpnp_pwm_chip *chip) if (pwm_config->pwm_value > max_pwm_value) pwm_config->pwm_value = max_pwm_value; + if (pwm_config->pwm_max_value + && (pwm_config->pwm_value > pwm_config->pwm_max_value)) + pwm_config->pwm_value = pwm_config->pwm_max_value; value = pwm_config->pwm_value; mask = QPNP_PWM_VALUE_LSB_MASK; @@ -839,6 +854,23 @@ static int qpnp_configure_lpg_control(struct qpnp_pwm_chip *chip) } +static int qpnp_configure_enable_lpg(struct qpnp_pwm_chip *chip) +{ + struct qpnp_lpg_config *lpg_config = &chip->lpg_config; + u8 value, mask; + + value = QPNP_ENABLE_LPG_MODE(chip); + + mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK | + QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK | + QPNP_PWM_EN_RAMP_GEN_MASK; + + return qpnp_lpg_save_and_write(value, mask, + &chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL], + SPMI_LPG_REG_ADDR(lpg_config->base_addr, + QPNP_ENABLE_CONTROL), 1, chip); +} + static int qpnp_lpg_configure_ramp_step_duration(struct qpnp_pwm_chip *chip) { struct qpnp_lpg_config *lpg_config = &chip->lpg_config; @@ -846,7 +878,7 @@ static int qpnp_lpg_configure_ramp_step_duration(struct qpnp_pwm_chip *chip) int rc, value; u8 val, mask; - value = QPNP_GET_RAMP_STEP_DURATION(lut_config.ramp_step_ms); + value = lut_config.ramp_step_ms; val = value & QPNP_RAMP_STEP_DURATION_LSB_MASK; mask = QPNP_RAMP_STEP_DURATION_LSB_MASK; @@ -1315,10 +1347,66 @@ after_table_write: return rc; } -/* lpg_lock should be held while calling _pwm_enable() */ +static int _pwm_config_lut(struct qpnp_pwm_chip *chip, + struct lut_config *pwm_lut) +{ + struct qpnp_lpg_config *lpg_config; + struct qpnp_lut_config *lut_config; + struct _qpnp_pwm_config *pwm_config; + int flags = pwm_lut->flags; + int raw_lut, ramp_step_ms; + int rc = 0; + + pwm_config = &chip->pwm_config; + lpg_config = &chip->lpg_config; + lut_config = &lpg_config->lut_config; + + raw_lut = 1; + + lut_config->list_len = pwm_lut->hi_index - pwm_lut->lo_index + 1; + if (lut_config->list_len < 0) { + pr_err("%s wrong LUT index\n", __func__); + return -EINVAL; + } + lut_config->lo_index = pwm_lut->lo_index; + lut_config->hi_index = pwm_lut->hi_index; + + rc = qpnp_lpg_change_table(chip, pwm_lut->lut, raw_lut); + if (rc) { + pr_err("qpnp_lpg_change_table: rc=%d\n", rc); + return -EINVAL; + } + + ramp_step_ms = pwm_lut->ramp_step_ms; + + lut_config->lut_pause_lo_cnt = pwm_lut->lut_pause_lo; + lut_config->lut_pause_hi_cnt = pwm_lut->lut_pause_hi; + + lut_config->ramp_step_ms = ramp_step_ms; + + lut_config->ramp_direction = !!(flags & PM_PWM_LUT_RAMP_UP); + lut_config->pattern_repeat = !!(flags & PM_PWM_LUT_LOOP); + lut_config->ramp_toggle = !!(flags & PM_PWM_LUT_REVERSE); + lut_config->enable_pause_hi = !!(flags & PM_PWM_LUT_PAUSE_HI_EN); + lut_config->enable_pause_lo = !!(flags & PM_PWM_LUT_PAUSE_LO_EN); + + rc = qpnp_lpg_change_lut(chip); + if (rc) { + pr_err("qpnp_lpg_change_lut: rc=%d\n", rc); + return -EINVAL; + } + + rc = qpnp_configure_enable_lpg(chip); + + return rc; +} + static int _pwm_enable(struct qpnp_pwm_chip *chip) { int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&chip->lpg_lock, flags); if (QPNP_IS_PWM_CONFIG_SELECTED( chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) || @@ -1331,21 +1419,8 @@ static int _pwm_enable(struct qpnp_pwm_chip *chip) if (!rc) chip->enabled = true; - return rc; -} - -/* lpg_lock should be held while calling _pwm_change_mode() */ -static int _pwm_change_mode(struct qpnp_pwm_chip *chip, enum pm_pwm_mode mode) -{ - int rc; - - if (mode == PM_PWM_MODE_LPG) - rc = qpnp_configure_lpg_control(chip); - else - rc = qpnp_configure_pwm_control(chip); + spin_unlock_irqrestore(&chip->lpg_lock, flags); - if (rc) - pr_err("Failed to change the mode\n"); return rc; } @@ -1422,15 +1497,11 @@ static int qpnp_pwm_enable(struct pwm_chip *pwm_chip, { int rc; struct qpnp_pwm_chip *chip = qpnp_pwm_from_pwm_chip(pwm_chip); - unsigned long flags; - spin_lock_irqsave(&chip->lpg_lock, flags); rc = _pwm_enable(chip); if (rc) pr_err("Failed to enable PWM channel: %d\n", chip->channel_id); - spin_unlock_irqrestore(&chip->lpg_lock, flags); - return rc; } @@ -1468,6 +1539,20 @@ static void qpnp_pwm_disable(struct pwm_chip *pwm_chip, chip->channel_id); } +static int _pwm_change_mode(struct qpnp_pwm_chip *chip, enum pm_pwm_mode mode) +{ + int rc; + + if (mode) + rc = qpnp_configure_lpg_control(chip); + else + rc = qpnp_configure_pwm_control(chip); + + if (rc) + pr_err("Failed to change the mode\n"); + return rc; +} + /** * pwm_change_mode - Change the PWM mode configuration * @pwm: the PWM device @@ -1492,22 +1577,7 @@ int pwm_change_mode(struct pwm_device *pwm, enum pm_pwm_mode mode) chip = qpnp_pwm_from_pwm_dev(pwm); spin_lock_irqsave(&chip->lpg_lock, flags); - if (chip->pwm_mode != mode) { - rc = _pwm_change_mode(chip, mode); - if (rc) { - pr_err("Failed to change mode: %d, rc=%d\n", mode, rc); - goto unlock; - } - chip->pwm_mode = mode; - if (chip->enabled) { - rc = _pwm_enable(chip); - if (rc) { - pr_err("Failed to enable PWM, rc=%d\n", rc); - goto unlock; - } - } - } -unlock: + rc = _pwm_change_mode(chip, mode); spin_unlock_irqrestore(&chip->lpg_lock, flags); return rc; @@ -1732,6 +1802,131 @@ int pwm_lut_config(struct pwm_device *pwm, int period_us, } EXPORT_SYMBOL(pwm_lut_config); +/** + * pwm_config_lut - change LPG LUT device configuration + * @pwm: the PWM device + * @pwm_lut: LUT config + */ +int pwm_config_lut(struct pwm_device *pwm, + struct lut_config *pwm_lut) +{ + unsigned long flags; + struct qpnp_pwm_chip *chip; + int rc = 0; + + if (pwm == NULL || IS_ERR(pwm)) { + pr_err("Invalid pwm handle\n"); + return -EINVAL; + } + + if (pwm_lut == NULL) { + pr_err("Invalid pwm_lut handle\n"); + return -EINVAL; + } + + chip = qpnp_pwm_from_pwm_dev(pwm); + + spin_lock_irqsave(&chip->lpg_lock, flags); + + rc = _pwm_config_lut(chip, pwm_lut); + + spin_unlock_irqrestore(&chip->lpg_lock, flags); + + if (rc) + pr_err("Failed to configure LUT\n"); + + return rc; +} +EXPORT_SYMBOL_GPL(pwm_config_lut); + +/** + * pwm_start_lut_ramp - start LUT ramp to sync + * + * @pwm: the PWM device + * @ramp_control: set bit corresponding to LPG channel. + */ +int pwm_start_lut_ramp(struct pwm_device *pwm, int ramp_control) +{ + struct qpnp_lpg_config *lpg_config; + struct qpnp_pwm_chip *chip; + u8 value, mask; + u8 *reg; + u16 addr; + + chip = qpnp_pwm_from_pwm_dev(pwm); + lpg_config = &chip->lpg_config; + + value = chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL]; + reg = &chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL]; + + mask = QPNP_LUT_RAMP_CONTROL_MASK; + value = mask & ramp_control; + + addr = lpg_config->lut_base_addr + + SPMI_LPG_REV1_RAMP_CONTROL_OFFSET; + + return qpnp_lpg_save_and_write(value, mask, reg, + addr, 1, chip); +} +EXPORT_SYMBOL_GPL(pwm_start_lut_ramp); + +/** + * pwm_config_period_value - change PWM period and pwm value + * + * @pwm: the PWM device + * @pwm_p: period in struct qpnp_lpg_period + * @pwm_value: PWM value + */ +int pwm_config_period_value(struct pwm_device *pwm, + struct pwm_period_config *pwm_p, int pwm_value) +{ + unsigned long flags; + struct qpnp_pwm_chip *chip; + int rc = pwm_config_period(pwm, pwm_p); + + if (rc) + return rc; + chip = qpnp_pwm_from_pwm_dev(pwm); + + spin_lock_irqsave(&chip->lpg_lock, flags); + /* need check argment */ + chip->pwm_config.pwm_value = pwm_value; + rc = qpnp_lpg_save_pwm_value(chip); + spin_unlock_irqrestore(&chip->lpg_lock, flags); + + return rc; +} +EXPORT_SYMBOL_GPL(pwm_config_period_value); + +int pwm_get_max_pwm_value(struct pwm_device *pwm) +{ + unsigned long flags; + struct qpnp_pwm_chip *chip; + int max; + + chip = qpnp_pwm_from_pwm_dev(pwm); + + spin_lock_irqsave(&chip->lpg_lock, flags); + max = chip->pwm_config.pwm_max_value; + spin_unlock_irqrestore(&chip->lpg_lock, flags); + + return max; +} +EXPORT_SYMBOL_GPL(pwm_get_max_pwm_value); + +void pwm_set_max_pwm_value(struct pwm_device *pwm, int max) +{ + unsigned long flags; + struct qpnp_pwm_chip *chip; + + chip = qpnp_pwm_from_pwm_dev(pwm); + + spin_lock_irqsave(&chip->lpg_lock, flags); + chip->pwm_config.pwm_max_value = max; + spin_unlock_irqrestore(&chip->lpg_lock, flags); +} +EXPORT_SYMBOL_GPL(pwm_set_max_pwm_value); + static int qpnp_parse_pwm_dt_config(struct device_node *of_pwm_node, struct device_node *of_parent, struct qpnp_pwm_chip *chip) { @@ -1911,7 +2106,7 @@ out: static int qpnp_parse_dt_config(struct platform_device *pdev, struct qpnp_pwm_chip *chip) { - int rc, mode, lut_entry_size, list_size, i; + int rc, enable, lut_entry_size, list_size, i; const char *label; const __be32 *prop; u32 size; @@ -2039,6 +2234,10 @@ static int qpnp_parse_dt_config(struct platform_device *pdev, kfree(lut_config->duty_pct_list); return rc; } + rc = of_property_read_u32(of_node, "qcom,pwm-max-value", + &chip->pwm_config.pwm_max_value); + if (rc) + chip->pwm_config.pwm_max_value = 0; } rc = of_property_read_u32(of_node, "qcom,dtest-line", @@ -2095,20 +2294,18 @@ static int qpnp_parse_dt_config(struct platform_device *pdev, } } - rc = of_property_read_u32(of_node, "qcom,mode-select", &mode); + rc = of_property_read_u32(of_node, "qcom,mode-select", &enable); if (rc) goto read_opt_props; - if (mode > PM_PWM_MODE_LPG || - (mode == PM_PWM_MODE_PWM && found_pwm_subnode == 0) || - (mode == PM_PWM_MODE_LPG && found_lpg_subnode == 0)) { + if ((enable == PM_PWM_MODE_PWM && found_pwm_subnode == 0) || + (enable == PM_PWM_MODE_LPG && found_lpg_subnode == 0)) { dev_err(&pdev->dev, "%s: Invalid mode select\n", __func__); rc = -EINVAL; goto out; } - chip->pwm_mode = mode; - _pwm_change_mode(chip, mode); + _pwm_change_mode(chip, enable); _pwm_enable(chip); read_opt_props: diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 068c7ddfb73912cc67248be9802fb1de749aa195..ab542179b3ec7a216891c2a469ebbbfa33825599 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1003,5 +1003,9 @@ config REGULATOR_STUB Clients can use the real regulator device names with proper constraint checking while the real driver is being developed. +config SOMC_LCD_OCP_ENABLED + bool "enable SoMC LCD OCP function" + help + Select this to enable SoMC LCD Over current protection function. endif diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 188920367e842fd4d21a032ff3c3412befbe7ac1..775496960e12acc3d6670d05b01b7e210a704bb5 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -12,6 +12,11 @@ * option) any later version. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -3454,6 +3459,33 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable) } EXPORT_SYMBOL_GPL(regulator_allow_bypass); +/* + * regulator_register_ocp_notification - register ocp notification + * @regulator: regulator source + * @notification: pointer of client ocp_notification + * + */ +int regulator_register_ocp_notification(struct regulator *regulator, + struct regulator_ocp_notification *notification) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret; + + mutex_lock(&rdev->mutex); + + /* sanity check */ + if (!rdev->desc->ops->register_ocp_notification) { + ret = -EINVAL; + goto out; + } + + ret = rdev->desc->ops->register_ocp_notification(rdev, notification); +out: + mutex_unlock(&rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_register_ocp_notification); + /** * regulator_register_notifier - register regulator event notifier * @regulator: regulator source diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c index 4d6d63e6d887b00f8856299323f66a90e98bc64a..ecf7885a4bffa3a2296228e25e79265200fb13cd 100644 --- a/drivers/regulator/cprh-kbss-regulator.c +++ b/drivers/regulator/cprh-kbss-regulator.c @@ -80,7 +80,7 @@ struct cprh_kbss_fuses { * Fuse combos 24 - 31 map to CPR fusing revision 0 - 7 with speed bin fuse = 3. */ #define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 32 -#define CPRH_SDM660_KBSS_FUSE_COMBO_COUNT 32 +#define CPRH_SDM660_KBSS_FUSE_COMBO_COUNT 16 #define CPRH_SDM630_KBSS_FUSE_COMBO_COUNT 24 /* @@ -1069,12 +1069,6 @@ static int cprh_kbss_calculate_open_loop_voltages(struct cpr3_regulator *vreg) CPRH_KBSS_FUSE_STEP_VOLT, fuse->init_voltage[i], CPRH_KBSS_VOLTAGE_FUSE_SIZE); - /* SDM660 speed bin #3 does not support TURBO_L1/L2 */ - if (soc_revision == SDM660_SOC_ID && vreg->speed_bin_fuse == 3 - && (id == CPRH_KBSS_PERFORMANCE_CLUSTER_ID) - && (i == CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2)) - continue; - /* Log fused open-loop voltage values for debugging purposes. */ cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n", corner_name[i], fuse_volt[i]); @@ -1621,11 +1615,6 @@ static int cprh_kbss_calculate_target_quotients(struct cpr3_regulator *vreg) CPRH_SDM660_PERF_KBSS_FUSE_CORNER_SVS; highest_fuse_corner = CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2; - - /* speed-bin 3 does not have Turbo_L2 fuse */ - if (vreg->speed_bin_fuse == 3) - highest_fuse_corner = - CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO; } break; case SDM630_SOC_ID: diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 499e437c7e919f2576c694ef6b6466898d006dbf..4e558d4d192d24b26f38997aae0bde07228bda36 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -9,6 +9,11 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c index 72c697bdcd2997c026b34a7aea726120b58caf7f..09213a71b6ec6dcfbf7cb2e71fd4ce8a908022b3 100644 --- a/drivers/regulator/qpnp-labibb-regulator.c +++ b/drivers/regulator/qpnp-labibb-regulator.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -17,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -31,6 +35,11 @@ #include #include #include +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +#include +#include +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ + #include #include @@ -38,7 +47,6 @@ #define REG_REVISION_2 0x01 #define REG_PERPH_TYPE 0x04 -#define REG_INT_RT_STS 0x10 #define QPNP_LAB_TYPE 0x24 #define QPNP_IBB_TYPE 0x20 @@ -51,6 +59,14 @@ /* LAB register offset definitions */ #define REG_LAB_STATUS1 0x08 +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +#define REG_LAB_INT_SET_TYPE 0x11 +#define REG_LAB_INT_POLARITY_HIGH 0x12 +#define REG_LAB_INT_POLARITY_LOW 0x13 +#define REG_LAB_INT_LATCHED_CLR 0x14 +#define REG_LAB_INT_EN_SET 0x15 +#define REG_LAB_INT_EN_CLR 0x16 +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ #define REG_LAB_SWIRE_PGM_CTL 0x40 #define REG_LAB_VOLTAGE 0x41 #define REG_LAB_RING_SUPPRESSION_CTL 0x42 @@ -78,8 +94,35 @@ /* LAB register bits definitions */ /* REG_LAB_STATUS1 */ -#define LAB_STATUS1_VREG_OK_BIT BIT(7) -#define LAB_STATUS1_SC_DETECT_BIT BIT(6) +#define LAB_STATUS1_VREG_OK_MASK BIT(7) +#define LAB_STATUS1_VREG_OK BIT(7) + +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +/* REG_LAB_INT_SET_TYPE */ +#define LAB_INT_SET_TYPE_VREG_OK_MASK BIT(0) +#define LAB_INT_SET_TYPE_VREG_OK_LEVEL 0 +#define LAB_INT_SET_TYPE_VREG_OK_EDGE 1 + +/* REG_LAB_INT_POLARITY_HIGH */ +#define LAB_INT_PRY_HIGH_VREG_OK_MASK BIT(0) +#define LAB_INT_PRY_HIGH_VREG_OK 0 + +/* REG_LAB_INT_POLARITY_LOW */ +#define LAB_INT_PRY_LOW_VREG_OK_MASK BIT(0) +#define LAB_INT_PRY_LOW_VREG_OK 1 + +/* REG_LAB_INT_LATCHED_CLR */ +#define LAB_INT_LATCHED_CLR_VREG_MASK BIT(0) +#define LAB_INT_LATCHED_CLR_VREG 1 + +/* REG_LAB_INT_EN_SET */ +#define LAB_INT_EN_SET_VREG_OK_MASK BIT(0) +#define LAB_INT_EN_SET_VREG_OK 1 + +/* REG_LAB_INT_EN_CLR */ +#define LAB_INT_EN_CLR_VREG_OK_MASK BIT(0) +#define LAB_INT_EN_CLR_VREG_OK 1 +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ /* REG_LAB_SWIRE_PGM_CTL */ #define LAB_EN_SWIRE_PGM_VOUT BIT(7) @@ -112,6 +155,10 @@ #define LAB_CURRENT_LIMIT_EN_BIT BIT(7) #define LAB_OVERRIDE_CURRENT_MAX_BIT BIT(3) +#ifdef SOMC_LABIBB_REGULATOR_ORG_IMPL +#define LAB_CURRENT_LIMIT_OVERRIDE BIT(3) +#endif /* SOMC_LABIBB_REGULATOR_ORG_IMPL */ + /* REG_LAB_CURRENT_SENSE */ #define LAB_CURRENT_SENSE_GAIN_MASK GENMASK(1, 0) @@ -154,6 +201,14 @@ /* IBB register offset definitions */ #define REG_IBB_REVISION4 0x03 #define REG_IBB_STATUS1 0x08 +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +#define REG_IBB_INT_SET_TYPE 0x11 +#define REG_IBB_INT_POLARITY_HIGH 0x12 +#define REG_IBB_INT_POLARITY_LOW 0x13 +#define REG_IBB_INT_LATCHED_CLR 0x14 +#define REG_IBB_INT_EN_SET 0x15 +#define REG_IBB_INT_EN_CLR 0x16 +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ #define REG_IBB_VOLTAGE 0x41 #define REG_IBB_RING_SUPPRESSION_CTL 0x42 #define REG_IBB_LCD_AMOLED_SEL 0x44 @@ -186,8 +241,35 @@ /* IBB register bits definition */ /* REG_IBB_STATUS1 */ -#define IBB_STATUS1_VREG_OK_BIT BIT(7) -#define IBB_STATUS1_SC_DETECT_BIT BIT(6) +#define IBB_STATUS1_VREG_OK_MASK BIT(7) +#define IBB_STATUS1_VREG_OK BIT(7) + +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +/* REG_IBB_INT_SET_TYPE */ +#define IBB_INT_SET_TYPE_VREG_OK_MASK BIT(0) +#define IBB_INT_SET_TYPE_VREG_OK_LEVEL 0 +#define IBB_INT_SET_TYPE_VREG_OK_EDGE 1 + +/* REG_IBB_INT_POLARITY_HIGH */ +#define IBB_INT_PRY_HIGH_VREG_OK_MASK BIT(0) +#define IBB_INT_PRY_HIGH_VREG_OK 1 + +/* REG_IBB_INT_POLARITY_LOW */ +#define IBB_INT_PRY_LOW_VREG_OK_MASK BIT(0) +#define IBB_INT_PRY_LOW_VREG_OK 0 + +/* REG_IBB_INT_LATCHED_CLR */ +#define IBB_INT_LATCHED_CLR_VREG_MASK BIT(0) +#define IBB_INT_LATCHED_CLR_VREG 1 + +/* REG_IBB_INT_EN_SET */ +#define IBB_INT_EN_SET_VREG_OK_MASK BIT(0) +#define IBB_INT_EN_SET_VREG_OK 1 + +/* REG_IBB_INT_EN_CLR */ +#define IBB_INT_EN_CLR_VREG_OK_MASK BIT(0) +#define IBB_INT_EN_CLR_VREG_OK 1 +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ /* REG_IBB_VOLTAGE */ #define IBB_VOLTAGE_OVERRIDE_EN BIT(7) @@ -230,6 +312,10 @@ #define IBB_ILIMIT_COUNT_CYC8 0 #define IBB_CURRENT_MAX_500MA 0xA +#ifdef SOMC_LABIBB_REGULATOR_ORG_IMPL +#define IBB_CURRENT_LIMIT_VALUE 16 +#endif /* SOMC_LABIBB_REGULATOR_ORG_IMPL */ + /* REG_IBB_PS_CTL */ #define IBB_PS_CTL_EN 0x85 @@ -306,6 +392,51 @@ #define IBB_DIS_DLY_MASK GENMASK(1, 0) #define IBB_WAIT_MBG_OK BIT(2) +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +/* enable_irq */ +#define ENABLE_IRQ(irq_num) \ +do { \ + pr_debug("ENABLE_IRQ: %s\n", __func__); \ + enable_irq(irq_num); \ +} while (0) + +/* disable_irq */ +#define DISABLE_IRQ(irq_num) \ +do { \ + pr_debug("DISABLE_IRQ_NOSYNC: %s\n", __func__); \ + disable_irq_nosync(irq_num); \ +} while (0) + +#define IRQF_LAB_FLAGS (IRQF_DISABLED | IRQF_ONESHOT | IRQF_TRIGGER_LOW) +#define IRQF_IBB_FLAGS (IRQF_DISABLED | IRQF_ONESHOT | IRQF_TRIGGER_HIGH) + +#define CHATTER_CNT_START 1 +#define DEFAULT_TARGET_CHATTER_CNT 3 +#define DEFAULT_TARGET_CHATTER_INTERVAL 500 +#define POWER_OFF_RETRY_INTERVAL 500 + +#define VREG_WORKER_ACTIVE true +#define VREG_WORKER_PASSIVE false + +static irqreturn_t ibb_vreg_handler(int irq, void *_chip); +static irqreturn_t lab_vreg_handler(int irq, void *_chip); + +static struct labibb_vreg_status_ctrl { + struct delayed_work vreg_check_work; + struct qpnp_labibb *labibb; + int current_chatter_cnt; + int target_chatter_cnt; + int target_chatter_check_interval; + bool vreg_check_working; + bool ocp_lab_detected; + bool ocp_ibb_detected; +} labibb_vreg_check; + +static int qpnp_ibb_register_irq(struct device_node *child, + struct qpnp_labibb *labibb); + +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ + /* Constants */ #define SWIRE_DEFAULT_2ND_CMD_DLY_MS 20 #define SWIRE_DEFAULT_IBB_PS_ENABLE_DLY_MS 200 @@ -321,6 +452,9 @@ * supported by qpnp_labibb_regulator */ enum qpnp_labibb_mode { +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + QPNP_LABIBB_STANDALONE_MODE = 1, +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ QPNP_LABIBB_LCD_MODE, QPNP_LABIBB_AMOLED_MODE, QPNP_LABIBB_MAX_MODE, @@ -555,8 +689,6 @@ struct lab_regulator { struct mutex lab_mutex; int lab_vreg_ok_irq; - int lab_sc_irq; - int curr_volt; int min_volt; @@ -573,8 +705,6 @@ struct ibb_regulator { struct regulator_dev *rdev; struct mutex ibb_mutex; - int ibb_sc_irq; - int curr_volt; int min_volt; @@ -605,9 +735,10 @@ struct qpnp_labibb { struct mutex bus_mutex; enum qpnp_labibb_mode mode; struct work_struct lab_vreg_ok_work; - struct delayed_work sc_err_recovery_work; - struct hrtimer sc_err_check_timer; - int sc_err_count; +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + int lab_vreg_irq; + int ibb_vreg_irq; +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ bool standalone; bool ttw_en; bool in_ttw_mode; @@ -1406,6 +1537,301 @@ static int qpnp_labibb_get_matching_idx(const char *val) return -EINVAL; } +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +static int qpnp_lab_interrupt_enable_ctl(struct qpnp_labibb *labibb, + bool inWork) +{ + int rc = 0; + + if (labibb_vreg_check.vreg_check_working && !inWork) { + pr_debug("%s: vreg_check_worker is already being processed.\n", + __func__); + goto exit; + } + + /* lab int latched clr */ + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_INT_LATCHED_CLR, + LAB_INT_LATCHED_CLR_VREG_MASK, + LAB_INT_LATCHED_CLR_VREG); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_LAB_INT_LATCHED_CLR, rc); + goto exit; + } + /* lab int en set */ + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_INT_EN_SET, + LAB_INT_EN_SET_VREG_OK_MASK, + LAB_INT_EN_SET_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_LAB_INT_EN_SET, rc); + goto exit; + } + ENABLE_IRQ(labibb->lab_vreg_irq); +exit: + return rc; +} + +static int qpnp_lab_interrupt_disable_ctl(struct qpnp_labibb *labibb) +{ + int rc = 0; + + if (labibb_vreg_check.vreg_check_working) { + pr_debug("%s: vreg_check_worker is already being processed.\n", + __func__); + goto exit; + } + + DISABLE_IRQ(labibb->lab_vreg_irq); + /* lab int en clr */ + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_INT_EN_CLR, + LAB_INT_EN_CLR_VREG_OK_MASK, + LAB_INT_EN_CLR_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_LAB_INT_EN_CLR, rc); + goto exit; + } +exit: + return rc; +} + +static int qpnp_ibb_interrupt_enable_ctl(struct qpnp_labibb *labibb, + bool inWork) +{ + int rc = 0; + + if (labibb_vreg_check.vreg_check_working && !inWork) { + pr_debug("%s: vreg_check_worker is already being processed.\n", + __func__); + goto exit; + } + + /* ibb int latched clr */ + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_INT_LATCHED_CLR, + IBB_INT_LATCHED_CLR_VREG_MASK, + IBB_INT_LATCHED_CLR_VREG); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_IBB_INT_LATCHED_CLR, rc); + goto exit; + } + /* ibb int en set */ + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_INT_EN_SET, + IBB_INT_EN_SET_VREG_OK_MASK, + IBB_INT_EN_SET_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_IBB_INT_EN_SET, rc); + goto exit; + } + ENABLE_IRQ(labibb->ibb_vreg_irq); +exit: + return rc; +} + +static int qpnp_ibb_interrupt_disable_ctl(struct qpnp_labibb *labibb) +{ + int rc = 0; + + if (labibb_vreg_check.vreg_check_working) { + pr_debug("%s: vreg_check_worker is already being processed.\n", + __func__); + goto exit; + } + + DISABLE_IRQ(labibb->ibb_vreg_irq); + /* ibb int en clr */ + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_INT_EN_CLR, + IBB_INT_EN_CLR_VREG_OK_MASK, + IBB_INT_EN_CLR_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_IBB_INT_EN_CLR, rc); + goto exit; + } +exit: + return rc; +} + +static int qpnp_labibb_interrupt_enable_ctl(struct qpnp_labibb *labibb, + bool inWork) +{ + int rc; + + rc = qpnp_lab_interrupt_enable_ctl(labibb, inWork); + if (rc) { + pr_err("%s: qpnp_lab_interrupt_enable_ctl failed rc = %d\n", + __func__, rc); + goto exit; + } + + rc = qpnp_ibb_interrupt_enable_ctl(labibb, inWork); + if (rc) { + pr_err("%s: qpnp_ibb_interrupt_enable_ctl failed rc = %d\n", + __func__, rc); + goto exit; + } + +exit: + return rc; +} + +static int qpnp_labibb_interrupt_disable_ctl(struct qpnp_labibb *labibb) +{ + int rc; + + rc = qpnp_lab_interrupt_disable_ctl(labibb); + if (rc) { + pr_err("%s: qpnp_lab_interrupt_disable_ctl failed rc = %d\n", + __func__, rc); + goto exit; + } + + rc = qpnp_ibb_interrupt_disable_ctl(labibb); + if (rc) { + pr_err("%s: qpnp_ibb_interrupt_disable_ctl failed rc = %d\n", + __func__, rc); + goto exit; + } + +exit: + return rc; +} + +static int qpnp_lab_request_interrupt(struct qpnp_labibb *labibb) +{ + int rc = 0; + + /* lab int set type */ + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_INT_SET_TYPE, + LAB_INT_SET_TYPE_VREG_OK_MASK, + LAB_INT_SET_TYPE_VREG_OK_LEVEL); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_LAB_INT_SET_TYPE, rc); + goto exit; + } + + /* lab int polarity high */ + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_INT_POLARITY_HIGH, + LAB_INT_PRY_HIGH_VREG_OK_MASK, + LAB_INT_PRY_HIGH_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_LAB_INT_POLARITY_HIGH, rc); + goto exit; + } + + /* lab int polarity low */ + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_INT_POLARITY_LOW, + LAB_INT_PRY_LOW_VREG_OK_MASK, + LAB_INT_PRY_LOW_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_LAB_INT_POLARITY_LOW, rc); + goto exit; + } + + /* lab int en set */ + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_INT_EN_SET, + LAB_INT_EN_SET_VREG_OK_MASK, + LAB_INT_EN_SET_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_LAB_INT_EN_SET, rc); + goto exit; + } + + /* lab int latched clr */ + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_INT_LATCHED_CLR, + LAB_INT_LATCHED_CLR_VREG_MASK, + LAB_INT_LATCHED_CLR_VREG); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_LAB_INT_LATCHED_CLR, rc); + goto exit; + } + +exit: + return rc; +} + +static int qpnp_ibb_request_interrupt(struct qpnp_labibb *labibb) +{ + int rc = 0; + + /* ibb int set type */ + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_INT_SET_TYPE, + IBB_INT_SET_TYPE_VREG_OK_MASK, + IBB_INT_SET_TYPE_VREG_OK_LEVEL); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_IBB_INT_SET_TYPE, rc); + goto exit; + } + + /* ibb int polarity high */ + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_INT_POLARITY_HIGH, + IBB_INT_PRY_HIGH_VREG_OK_MASK, + IBB_INT_PRY_HIGH_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_IBB_INT_POLARITY_HIGH, rc); + goto exit; + } + + /* IBB int polarity low */ + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_INT_POLARITY_LOW, + IBB_INT_PRY_LOW_VREG_OK_MASK, + IBB_INT_PRY_LOW_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_IBB_INT_POLARITY_LOW, rc); + goto exit; + } + + /* ibb int en set */ + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_INT_EN_SET, + IBB_INT_EN_SET_VREG_OK_MASK, + IBB_INT_EN_SET_VREG_OK); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_IBB_INT_EN_SET, rc); + goto exit; + } + + /* ibb int latched clr */ + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_INT_LATCHED_CLR, + IBB_INT_LATCHED_CLR_VREG_MASK, + IBB_INT_LATCHED_CLR_VREG); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_IBB_INT_LATCHED_CLR, rc); + goto exit; + } + +exit: + return rc; +} +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ + static int qpnp_ibb_set_mode(struct qpnp_labibb *labibb, enum ibb_mode mode) { int rc; @@ -1512,6 +1938,9 @@ static int qpnp_lab_dt_init(struct qpnp_labibb *labibb, if (of_property_read_bool(of_node, "qcom,qpnp-lab-limit-max-current-enable")) { val = LAB_CURRENT_LIMIT_EN_BIT; +#ifdef SOMC_LABIBB_REGULATOR_ORG_IMPL + val |= LAB_CURRENT_LIMIT_OVERRIDE; +#endif /* SOMC_LABIBB_REGULATOR_ORG_IMPL */ rc = of_property_read_u32(of_node, "qcom,qpnp-lab-limit-maximum-current", &tmp); @@ -2162,7 +2591,7 @@ static void qpnp_lab_vreg_notifier_work(struct work_struct *work) return; } - if (val & LAB_STATUS1_VREG_OK_BIT) { + if (val & LAB_STATUS1_VREG_OK) { raw_notifier_call_chain(&labibb_notifier, LAB_VREG_OK, NULL); break; @@ -2195,74 +2624,6 @@ static void qpnp_lab_vreg_notifier_work(struct work_struct *work) } } -static int qpnp_lab_enable_standalone(struct qpnp_labibb *labibb) -{ - int rc; - u8 val; - - val = LAB_ENABLE_CTL_EN; - rc = qpnp_labibb_write(labibb, - labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); - if (rc < 0) { - pr_err("Write register %x failed rc = %d\n", - REG_LAB_ENABLE_CTL, rc); - return rc; - } - - udelay(labibb->lab_vreg.soft_start); - - rc = qpnp_labibb_read(labibb, labibb->lab_base + - REG_LAB_STATUS1, &val, 1); - if (rc < 0) { - pr_err("Read register %x failed rc = %d\n", - REG_LAB_STATUS1, rc); - return rc; - } - - if (!(val & LAB_STATUS1_VREG_OK_BIT)) { - pr_err("Can't enable LAB standalone\n"); - return -EINVAL; - } - - return 0; -} - -static int qpnp_ibb_enable_standalone(struct qpnp_labibb *labibb) -{ - int rc, delay, retries = 10; - u8 val; - - rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN); - if (rc < 0) { - pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); - return rc; - } - - delay = labibb->ibb_vreg.soft_start; - while (retries--) { - /* Wait for a small period before reading IBB_STATUS1 */ - usleep_range(delay, delay + 100); - - rc = qpnp_labibb_read(labibb, labibb->ibb_base + - REG_IBB_STATUS1, &val, 1); - if (rc < 0) { - pr_err("Read register %x failed rc = %d\n", - REG_IBB_STATUS1, rc); - return rc; - } - - if (val & IBB_STATUS1_VREG_OK_BIT) - break; - } - - if (!(val & IBB_STATUS1_VREG_OK_BIT)) { - pr_err("Can't enable IBB standalone\n"); - return -EINVAL; - } - - return 0; -} - static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) { int rc; @@ -2304,7 +2665,7 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) labibb->lab_vreg.soft_start, labibb->ibb_vreg.soft_start, labibb->ibb_vreg.pwrup_dly, dly); - if (!(val & LAB_STATUS1_VREG_OK_BIT)) { + if (!(val & LAB_STATUS1_VREG_OK)) { pr_err("failed for LAB %x\n", val); goto err_out; } @@ -2321,7 +2682,7 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) goto err_out; } - if (val & IBB_STATUS1_VREG_OK_BIT) { + if (val & IBB_STATUS1_VREG_OK) { enabled = true; break; } @@ -2335,6 +2696,9 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) labibb->lab_vreg.vreg_enabled = 1; labibb->ibb_vreg.vreg_enabled = 1; +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + qpnp_labibb_interrupt_enable_ctl(labibb, VREG_WORKER_PASSIVE); +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ return 0; err_out: @@ -2354,6 +2718,10 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) int retries; bool disabled = false; +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + qpnp_labibb_interrupt_disable_ctl(labibb); +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ + /* * When TTW mode is enabled and LABIBB regulators are disabled, it is * recommended not to disable IBB through IBB_ENABLE_CTL when switching @@ -2392,7 +2760,7 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) return rc; } - if (!(val & IBB_STATUS1_VREG_OK_BIT)) { + if (!(val & IBB_STATUS1_VREG_OK)) { disabled = true; break; } @@ -2421,6 +2789,8 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) static int qpnp_lab_regulator_enable(struct regulator_dev *rdev) { int rc; + u8 val; + struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); if (labibb->sc_detected) { @@ -2437,15 +2807,38 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev) } if (!labibb->lab_vreg.vreg_enabled && !labibb->swire_control) { + if (!labibb->standalone) return qpnp_labibb_regulator_enable(labibb); - rc = qpnp_lab_enable_standalone(labibb); - if (rc) { - pr_err("enable lab standalone failed, rc=%d\n", rc); + val = LAB_ENABLE_CTL_EN; + rc = qpnp_labibb_write(labibb, + labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); + if (rc < 0) { + pr_err("qpnp_lab_regulator_enable write register %x failed rc = %d\n", + REG_LAB_ENABLE_CTL, rc); + return rc; + } + + udelay(labibb->lab_vreg.soft_start); + + rc = qpnp_labibb_read(labibb, labibb->lab_base + + REG_LAB_STATUS1, &val, 1); + if (rc < 0) { + pr_err("qpnp_lab_regulator_enable read register %x failed rc = %d\n", + REG_LAB_STATUS1, rc); return rc; } + + if ((val & LAB_STATUS1_VREG_OK_MASK) != LAB_STATUS1_VREG_OK) { + pr_err("qpnp_lab_regulator_enable failed\n"); + return -EINVAL; + } + labibb->lab_vreg.vreg_enabled = 1; +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + qpnp_lab_interrupt_enable_ctl(labibb, VREG_WORKER_PASSIVE); +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ } if (labibb->notify_lab_vreg_ok_sts || labibb->detect_lab_sc) @@ -2464,6 +2857,9 @@ static int qpnp_lab_regulator_disable(struct regulator_dev *rdev) if (!labibb->standalone) return qpnp_labibb_regulator_disable(labibb); +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + qpnp_lab_interrupt_disable_ctl(labibb); +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ val = 0; rc = qpnp_labibb_write(labibb, @@ -2489,188 +2885,31 @@ static int qpnp_lab_regulator_is_enabled(struct regulator_dev *rdev) return labibb->lab_vreg.vreg_enabled; } -static int qpnp_labibb_force_enable(struct qpnp_labibb *labibb) +static int qpnp_lab_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned int *selector) { - int rc; + int rc, new_uV; + u8 val; + struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); - if (labibb->skip_2nd_swire_cmd) { - rc = qpnp_ibb_ps_config(labibb, false); - if (rc < 0) { - pr_err("Failed to disable IBB PS rc=%d\n", rc); - return rc; - } + if (labibb->swire_control) + return 0; + + if (min_uV < labibb->lab_vreg.min_volt) { + pr_err("min_uV %d is less than min_volt %d", min_uV, + labibb->lab_vreg.min_volt); + return -EINVAL; } - if (!labibb->swire_control) { - if (!labibb->standalone) - return qpnp_labibb_regulator_enable(labibb); + val = DIV_ROUND_UP(min_uV - labibb->lab_vreg.min_volt, + labibb->lab_vreg.step_size); + new_uV = val * labibb->lab_vreg.step_size + labibb->lab_vreg.min_volt; - rc = qpnp_ibb_enable_standalone(labibb); - if (rc < 0) { - pr_err("enable ibb standalone failed, rc=%d\n", rc); - return rc; - } - labibb->ibb_vreg.vreg_enabled = 1; - - rc = qpnp_lab_enable_standalone(labibb); - if (rc < 0) { - pr_err("enable lab standalone failed, rc=%d\n", rc); - return rc; - } - labibb->lab_vreg.vreg_enabled = 1; - } - - return 0; -} - -#define SC_ERR_RECOVERY_DELAY_MS 250 -#define SC_ERR_COUNT_INTERVAL_SEC 1 -#define POLLING_SCP_DONE_COUNT 2 -#define POLLING_SCP_DONE_INTERVAL_MS 5 -static irqreturn_t labibb_sc_err_handler(int irq, void *_labibb) -{ - int rc; - u16 reg; - u8 sc_err_mask, val; - char *str; - struct qpnp_labibb *labibb = (struct qpnp_labibb *)_labibb; - bool in_sc_err, lab_en, ibb_en, scp_done = false; - int count; - - if (irq == labibb->lab_vreg.lab_sc_irq) { - reg = labibb->lab_base + REG_LAB_STATUS1; - sc_err_mask = LAB_STATUS1_SC_DETECT_BIT; - str = "LAB"; - } else if (irq == labibb->ibb_vreg.ibb_sc_irq) { - reg = labibb->ibb_base + REG_IBB_STATUS1; - sc_err_mask = IBB_STATUS1_SC_DETECT_BIT; - str = "IBB"; - } else { - return IRQ_HANDLED; - } - - rc = qpnp_labibb_read(labibb, reg, &val, 1); - if (rc < 0) { - pr_err("Read 0x%x failed, rc=%d\n", reg, rc); - return IRQ_HANDLED; - } - pr_debug("%s SC error triggered! %s_STATUS1 = %d\n", str, str, val); - - in_sc_err = !!(val & sc_err_mask); - - /* - * The SC fault would trigger PBS to disable regulators - * for protection. This would cause the SC_DETECT status being - * cleared so that it's not able to get the SC fault status. - * Check if LAB/IBB regulators are enabled in the driver but - * disabled in hardware, this means a SC fault had happened - * and SCP handling is completed by PBS. - */ - if (!in_sc_err) { - count = POLLING_SCP_DONE_COUNT; - do { - reg = labibb->lab_base + REG_LAB_ENABLE_CTL; - rc = qpnp_labibb_read(labibb, reg, &val, 1); - if (rc < 0) { - pr_err("Read 0x%x failed, rc=%d\n", reg, rc); - return IRQ_HANDLED; - } - lab_en = !!(val & LAB_ENABLE_CTL_EN); - - reg = labibb->ibb_base + REG_IBB_ENABLE_CTL; - rc = qpnp_labibb_read(labibb, reg, &val, 1); - if (rc < 0) { - pr_err("Read 0x%x failed, rc=%d\n", reg, rc); - return IRQ_HANDLED; - } - ibb_en = !!(val & IBB_ENABLE_CTL_MODULE_EN); - if (lab_en || ibb_en) - msleep(POLLING_SCP_DONE_INTERVAL_MS); - else - break; - } while ((lab_en || ibb_en) && count--); - - if (labibb->lab_vreg.vreg_enabled - && labibb->ibb_vreg.vreg_enabled - && !lab_en && !ibb_en) { - pr_debug("LAB/IBB has been disabled by SCP\n"); - scp_done = true; - } - } - - if (in_sc_err || scp_done) { - if (hrtimer_active(&labibb->sc_err_check_timer) || - hrtimer_callback_running(&labibb->sc_err_check_timer)) { - labibb->sc_err_count++; - } else { - labibb->sc_err_count = 1; - hrtimer_start(&labibb->sc_err_check_timer, - ktime_set(SC_ERR_COUNT_INTERVAL_SEC, 0), - HRTIMER_MODE_REL); - } - schedule_delayed_work(&labibb->sc_err_recovery_work, - msecs_to_jiffies(SC_ERR_RECOVERY_DELAY_MS)); - } - - return IRQ_HANDLED; -} - -#define SC_FAULT_COUNT_MAX 4 -static enum hrtimer_restart labibb_check_sc_err_count(struct hrtimer *timer) -{ - struct qpnp_labibb *labibb = container_of(timer, - struct qpnp_labibb, sc_err_check_timer); - /* - * if SC fault triggers more than 4 times in 1 second, - * then disable the IRQs and leave as it. - */ - if (labibb->sc_err_count > SC_FAULT_COUNT_MAX) { - disable_irq(labibb->lab_vreg.lab_sc_irq); - disable_irq(labibb->ibb_vreg.ibb_sc_irq); - } - - return HRTIMER_NORESTART; -} - -static void labibb_sc_err_recovery_work(struct work_struct *work) -{ - struct qpnp_labibb *labibb = container_of(work, struct qpnp_labibb, - sc_err_recovery_work.work); - int rc; - - labibb->ibb_vreg.vreg_enabled = 0; - labibb->lab_vreg.vreg_enabled = 0; - rc = qpnp_labibb_force_enable(labibb); - if (rc < 0) - pr_err("force enable labibb failed, rc=%d\n", rc); - -} - -static int qpnp_lab_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned int *selector) -{ - int rc, new_uV; - u8 val; - struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); - - if (labibb->swire_control) - return 0; - - if (min_uV < labibb->lab_vreg.min_volt) { - pr_err("min_uV %d is less than min_volt %d", min_uV, - labibb->lab_vreg.min_volt); - return -EINVAL; - } - - val = DIV_ROUND_UP(min_uV - labibb->lab_vreg.min_volt, - labibb->lab_vreg.step_size); - new_uV = val * labibb->lab_vreg.step_size + labibb->lab_vreg.min_volt; - - if (new_uV > max_uV) { - pr_err("unable to set voltage %d (min:%d max:%d)\n", new_uV, - min_uV, max_uV); - return -EINVAL; - } + if (new_uV > max_uV) { + pr_err("unable to set voltage %d (min:%d max:%d)\n", new_uV, + min_uV, max_uV); + return -EINVAL; + } rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + REG_LAB_VOLTAGE, @@ -2707,7 +2946,7 @@ static int qpnp_skip_swire_command(struct qpnp_labibb *labibb) pr_err("Failed to read ibb_status1 reg rc=%d\n", rc); return rc; } - if (reg & IBB_STATUS1_VREG_OK_BIT) + if ((reg & IBB_STATUS1_VREG_OK_MASK) == IBB_STATUS1_VREG_OK) break; /* poll delay */ @@ -3026,33 +3265,41 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, } labibb->lab_vreg.vreg_enabled = 1; - } +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + /* request interrupt */ + rc = qpnp_lab_request_interrupt(labibb); + if (rc) { + pr_err("lab request interrupt failed rc=%d\n", + rc); + return rc; + } - if (is_lab_vreg_ok_irq_available(labibb)) { rc = devm_request_threaded_irq(labibb->dev, - labibb->lab_vreg.lab_vreg_ok_irq, NULL, - lab_vreg_ok_handler, - IRQF_ONESHOT | IRQF_TRIGGER_RISING, - "lab-vreg-ok", labibb); + labibb->lab_vreg_irq, NULL, + lab_vreg_handler, + IRQF_LAB_FLAGS, + "lab_vreg_not_ok_interrupt", labibb); if (rc) { - pr_err("Failed to register 'lab-vreg-ok' irq rc=%d\n", + pr_err("Failed to register 'lab_vreg_not_ok_interrupt' irq rc=%d\n", rc); return rc; } +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ } - if (labibb->lab_vreg.lab_sc_irq != -EINVAL) { + if (is_lab_vreg_ok_irq_available(labibb)) { rc = devm_request_threaded_irq(labibb->dev, - labibb->lab_vreg.lab_sc_irq, NULL, - labibb_sc_err_handler, + labibb->lab_vreg.lab_vreg_ok_irq, NULL, + lab_vreg_ok_handler, IRQF_ONESHOT | IRQF_TRIGGER_RISING, - "lab-sc-err", labibb); + "lab-vreg-ok", labibb); if (rc) { - pr_err("Failed to register 'lab-sc-err' irq rc=%d\n", + pr_err("Failed to register 'lab-vreg-ok' irq rc=%d\n", rc); return rc; } } + rc = qpnp_labibb_read(labibb, labibb->lab_base + REG_LAB_MODULE_RDY, &val, 1); if (rc < 0) { @@ -3110,6 +3357,121 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, return 0; } +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +static void force_labibb_regulator_disable(struct qpnp_labibb *labibb) +{ + int rc; + u8 val; + + val = 0; + rc = qpnp_labibb_write(labibb, + labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_IBB_ENABLE_CTL, rc); + goto exit; + } + + if (labibb->mode != QPNP_LABIBB_STANDALONE_MODE) + goto exit; + + val = 0; + rc = qpnp_labibb_write(labibb, + labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); + if (rc) { + pr_err("%s: write register %x failed rc = %d\n", + __func__, REG_LAB_ENABLE_CTL, rc); + goto exit; + } +exit: + return; +} + +static void vreg_check_worker(struct work_struct *work) +{ + u8 val; + int rc; + struct qpnp_labibb *labibb = labibb_vreg_check.labibb; + + if ((!labibb->lab_vreg.vreg_enabled) || + (!labibb->ibb_vreg.vreg_enabled)) { + pr_debug("%s: false detection display is off\n", __func__); + goto exit; + } + + /* lab vreg status check */ + rc = qpnp_labibb_read(labibb, + labibb->lab_base + REG_LAB_STATUS1, + &val, + 1); + if (rc) { + pr_err("%s: read register %x failed rc = %d\n", + __func__, REG_LAB_STATUS1, rc); + goto read_error; + } + + if (!(val & LAB_STATUS1_VREG_OK)) + goto status_error; + + /* ibb vreg status check */ + rc = qpnp_labibb_read(labibb, + labibb->ibb_base + REG_IBB_STATUS1, + &val, + 1); + if (rc) { + pr_err("%s: read register %x failed rc = %d\n", + __func__, REG_IBB_STATUS1, rc); + goto read_error; + } + + if (!(val & IBB_STATUS1_VREG_OK)) + goto status_error; + + rc = qpnp_labibb_interrupt_enable_ctl(labibb, VREG_WORKER_ACTIVE); + if (rc) { + pr_err("%s: qpnp_labibb_interrupt_enable_ctl error\n", + __func__); + goto write_error; + } + + pr_debug("%s: vreg_check_worker done.\n", __func__); + goto exit; + +status_error: + labibb_vreg_check.current_chatter_cnt++; + pr_err("%s: VREG_NG Detection [%d]\n", + __func__, labibb_vreg_check.current_chatter_cnt); + if (labibb_vreg_check.current_chatter_cnt >= + labibb_vreg_check.target_chatter_cnt) { + pr_err("%s: execute shutdown.\n", __func__); + + /* disable vreg */ + force_labibb_regulator_disable(labibb); + /* shutdown */ + do { + pm_power_off(); + msleep(POWER_OFF_RETRY_INTERVAL); + } while (1); + goto exit; + } + +read_error: +write_error: + schedule_delayed_work(&labibb_vreg_check.vreg_check_work, + msecs_to_jiffies( + labibb_vreg_check.target_chatter_check_interval)); + return; + +exit: + /* initialize */ + labibb_vreg_check.current_chatter_cnt = 0; + labibb_vreg_check.vreg_check_working = false; + labibb_vreg_check.ocp_lab_detected = false; + labibb_vreg_check.ocp_ibb_detected = false; + return; +} +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ + static int qpnp_ibb_pfm_mode_enable(struct qpnp_labibb *labibb, struct device_node *of_node) { @@ -3259,6 +3621,253 @@ static bool qpnp_ibb_poff_ctl_required(struct qpnp_labibb *labibb) return true; } +#ifdef SOMC_LABIBB_REGULATOR_ORG_IMPL +/** This API is used to set precharge of LAB regulator + * regulator: the reglator device + * time: precharge time + * en: precharge control enable or not + */ +int qpnp_lab_set_precharge(struct regulator *regulator, u32 time, bool en) +{ + struct qpnp_labibb *labibb; + u8 val; + int rc; + + labibb = regulator_get_drvdata(regulator); + + for (val = 0; val < ARRAY_SIZE(lab_max_precharge_table); val++) + if (lab_max_precharge_table[val] == time) + break; + + if (val == ARRAY_SIZE(lab_max_precharge_table)) + val = ARRAY_SIZE(lab_max_precharge_table) - 1; + + if (en) + val |= LAB_FAST_PRECHARGE_CTL_EN; + + pr_debug("write base=0x%x val=0x%x\n", + (labibb->lab_base + REG_LAB_PRECHARGE_CTL), val); + + mutex_lock(&(labibb->lab_vreg.lab_mutex)); + + rc = qpnp_labibb_write(labibb, labibb->lab_base + + REG_LAB_PRECHARGE_CTL, &val, 1); + + mutex_unlock(&(labibb->lab_vreg.lab_mutex)); + return rc; +} +EXPORT_SYMBOL(qpnp_lab_set_precharge); + +/** This API is used to set soft-start of LAB regulator + * regulator: the reglator device + * time: soft start time + */ +int qpnp_lab_set_soft_start(struct regulator *regulator, u32 time) +{ + struct qpnp_labibb *labibb; + u8 val; + int rc; + + labibb = regulator_get_drvdata(regulator); + + for (val = 0; val < sizeof(ARRAY_SIZE(lab_soft_start_table)); val++) + if (lab_soft_start_table[val] == time) + break; + + if (val == ARRAY_SIZE(lab_soft_start_table)) + val = ARRAY_SIZE(lab_soft_start_table) - 1; + + pr_debug("write base=0x%x val=0x%x\n", + (labibb->lab_base + REG_LAB_SOFT_START_CTL), val); + + mutex_lock(&(labibb->lab_vreg.lab_mutex)); + + rc = qpnp_labibb_write(labibb, labibb->lab_base + + REG_LAB_SOFT_START_CTL, &val, 1); + + mutex_unlock(&(labibb->lab_vreg.lab_mutex)); + return rc; +} +EXPORT_SYMBOL(qpnp_lab_set_soft_start); + +/** This API is used to set pull-down of LAB regulator + * regulator: the reglator device + * en: pull-down enable or not + * strength: strength pull-down + */ +int qpnp_lab_set_pull_down(struct regulator *regulator, u8 strength) +{ + struct qpnp_labibb *labibb; + u8 val; + int rc = 0; + + labibb = regulator_get_drvdata(regulator); + + if (strength > 0) + val = LAB_PD_CTL_STRONG_PULL; + else + val = 0; + + mutex_lock(&(labibb->lab_vreg.lab_mutex)); + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_PD_CTL, + LAB_PD_CTL_STRENGTH_MASK, + val); + mutex_unlock(&(labibb->lab_vreg.lab_mutex)); + + if (rc) + pr_err("qpnp_lab_set_pd_strength write register %x failed rc = %d\n", + REG_LAB_PD_CTL, rc); + + return rc; +} +EXPORT_SYMBOL(qpnp_lab_set_pull_down); + +/** This API is used to set current max of LAB regulator + * regulator: the reglator device + * limit: current max of LAB regulator + */ +int qpnp_lab_set_current_max(struct regulator *regulator, u32 limit) +{ + struct qpnp_labibb *labibb; + int rc = 0; + u8 reg; + + labibb = regulator_get_drvdata(regulator); + + for (reg = 0; reg < ARRAY_SIZE(lab_current_limit_table); reg++) + if (lab_current_limit_table[reg] == limit) + break; + + if (reg == ARRAY_SIZE(lab_current_limit_table)) + reg = ARRAY_SIZE(lab_current_limit_table) - 1; + + pr_debug("write base=0x%x val=0x%x\n", + (labibb->lab_base + REG_LAB_CURRENT_LIMIT), reg); + + mutex_lock(&(labibb->lab_vreg.lab_mutex)); + + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_CURRENT_LIMIT, + LAB_CURRENT_LIMIT_MASK, + reg); + if (rc) + pr_err("%s write register %x failed rc = %d\n", + __func__, REG_LAB_CURRENT_LIMIT, rc); + + mutex_unlock(&(labibb->lab_vreg.lab_mutex)); + return rc; +} +EXPORT_SYMBOL(qpnp_lab_set_current_max); + +/** This API is used to set soft-start of IBB regulator + * regulator: the reglator device + * time: soft start time + */ +int qpnp_ibb_set_soft_start(struct regulator *regulator, u32 time) +{ + struct qpnp_labibb *labibb; + u8 val; + int rc; + + labibb = regulator_get_drvdata(regulator); + + for (val = 0; val < sizeof(ARRAY_SIZE(ibb_dischg_res_table)); + val++) + if (ibb_dischg_res_table[val] == time) + break; + + if (val == ARRAY_SIZE(ibb_dischg_res_table)) + val = ARRAY_SIZE(ibb_dischg_res_table) - 1; + + pr_debug("write base=0x%x val=0x%x\n", + (labibb->ibb_base + REG_IBB_SOFT_START_CTL), val); + + mutex_lock(&(labibb->ibb_vreg.ibb_mutex)); + + rc = qpnp_labibb_write(labibb, labibb->ibb_base + + REG_IBB_SOFT_START_CTL, &val, 1); + + mutex_unlock(&(labibb->ibb_vreg.ibb_mutex)); + return rc; +} +EXPORT_SYMBOL(qpnp_ibb_set_soft_start); + +/** This API is used to set pull-down of IBB regulator + * regulator: the reglator device + * en: pull-down enable or not + * strength: strength pull-down + */ +int qpnp_ibb_set_pull_down(struct regulator *regulator, u8 strength) +{ + struct qpnp_labibb *labibb; + u8 val; + int rc = 0; + + labibb = regulator_get_drvdata(regulator); + + if (strength > 0) + val = 0; + else + val = IBB_PD_CTL_HALF_STRENGTH; + + mutex_lock(&(labibb->ibb_vreg.ibb_mutex)); + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_PD_CTL, + IBB_PD_CTL_STRENGTH_MASK, + val); + mutex_unlock(&(labibb->ibb_vreg.ibb_mutex)); + + if (rc) + pr_err("qpnp_ibb_set_pd_strength write register %x failed rc = %d\n", + REG_IBB_PD_CTL, rc); + + return rc; +} +EXPORT_SYMBOL(qpnp_ibb_set_pull_down); + +/** This API is used to set current max of IBB regulator + * regulator: the reglator device + * limit: current max of IBB regulator + */ +int qpnp_ibb_set_current_max(struct regulator *regulator, u32 limit) +{ + struct qpnp_labibb *labibb; + int rc = 0; + u8 reg = 0; + + labibb = regulator_get_drvdata(regulator); + + reg = IBB_CURRENT_LIMIT_VALUE; + + if (!(ibb_current_limit_table[reg] == limit)) { + pr_err("%s value mismatch\n", __func__); + return rc; + } + + if (reg == ARRAY_SIZE(ibb_current_limit_table)) + reg = ARRAY_SIZE(ibb_current_limit_table) - 1; + + pr_debug("write base=0x%x val=0x%x\n", + (labibb->ibb_base + REG_IBB_CURRENT_LIMIT), reg); + + mutex_lock(&(labibb->ibb_vreg.ibb_mutex)); + + rc = qpnp_labibb_sec_masked_write(labibb, labibb->ibb_base, + REG_IBB_CURRENT_LIMIT, + IBB_CURRENT_LIMIT_MASK, + reg); + + if (rc) + pr_err("%s write register %x failed rc = %d\n", + __func__, REG_IBB_CURRENT_LIMIT, rc); + + mutex_unlock(&(labibb->ibb_vreg.ibb_mutex)); + return rc; +} +EXPORT_SYMBOL(qpnp_ibb_set_current_max); +#endif /* SOMC_LABIBB_REGULATOR_ORG_IMPL */ + static int qpnp_ibb_dt_init(struct qpnp_labibb *labibb, struct device_node *of_node) { @@ -3511,7 +4120,8 @@ static int qpnp_ibb_dt_init(struct qpnp_labibb *labibb, static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) { - int rc = 0; + int rc, delay, retries = 10; + u8 val; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); if (labibb->sc_detected) { @@ -3520,17 +4130,43 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) } if (!labibb->ibb_vreg.vreg_enabled && !labibb->swire_control) { + if (!labibb->standalone) return qpnp_labibb_regulator_enable(labibb); - rc = qpnp_ibb_enable_standalone(labibb); + rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN); if (rc < 0) { - pr_err("enable ibb standalone failed, rc=%d\n", rc); + pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } + + delay = labibb->ibb_vreg.soft_start; + while (retries--) { + /* Wait for a small period before reading IBB_STATUS1 */ + usleep_range(delay, delay + 100); + + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + REG_IBB_STATUS1, &val, 1); + if (rc < 0) { + pr_err("qpnp_ibb_regulator_enable read register %x failed rc = %d\n", + REG_IBB_STATUS1, rc); + return rc; + } + + if (val & IBB_STATUS1_VREG_OK) + break; + } + + if (!(val & IBB_STATUS1_VREG_OK)) { + pr_err("qpnp_ibb_regulator_enable failed\n"); + return -EINVAL; + } + labibb->ibb_vreg.vreg_enabled = 1; +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + qpnp_ibb_interrupt_enable_ctl(labibb, VREG_WORKER_PASSIVE); +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ } - return 0; } @@ -3539,6 +4175,10 @@ static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev) int rc; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + qpnp_ibb_interrupt_disable_ctl(labibb); +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ + if (labibb->ibb_vreg.vreg_enabled && !labibb->swire_control) { if (!labibb->standalone) @@ -3579,6 +4219,7 @@ static int qpnp_ibb_regulator_set_voltage(struct regulator_dev *rdev, return rc; } + static int qpnp_ibb_regulator_get_voltage(struct regulator_dev *rdev) { struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); @@ -3741,6 +4382,26 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, labibb->ibb_vreg.pwrdn_dly = ibb_pwrdn_dly_table[index]; labibb->ibb_vreg.vreg_enabled = 1; +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + /* request interrupt */ + rc = qpnp_ibb_request_interrupt(labibb); + if (rc) { + pr_err("ibb request interrupt failed rc=%d\n", + rc); + return rc; + } + + rc = devm_request_threaded_irq(labibb->dev, + labibb->ibb_vreg_irq, NULL, + ibb_vreg_handler, + IRQF_IBB_FLAGS, + "ibb_vreg_not_ok_interrupt", labibb); + if (rc) { + pr_err("Failed to register 'ibb_vreg_not_ok_interrupt' irq rc=%d\n", + rc); + return rc; + } +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ } else { /* SWIRE_RDY and IBB_MODULE_EN not enabled */ rc = qpnp_ibb_dt_init(labibb, of_node); @@ -3800,19 +4461,6 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, labibb->ibb_vreg.pwrdn_dly = 0; } - if (labibb->ibb_vreg.ibb_sc_irq != -EINVAL) { - rc = devm_request_threaded_irq(labibb->dev, - labibb->ibb_vreg.ibb_sc_irq, NULL, - labibb_sc_err_handler, - IRQF_ONESHOT | IRQF_TRIGGER_RISING, - "ibb-sc-err", labibb); - if (rc) { - pr_err("Failed to register 'ibb-sc-err' irq rc=%d\n", - rc); - return rc; - } - } - rc = qpnp_labibb_read(labibb, labibb->ibb_base + REG_IBB_MODULE_RDY, &val, 1); if (rc < 0) { @@ -3883,42 +4531,40 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, return 0; } -static int qpnp_lab_register_irq(struct device_node *child, +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +static int qpnp_ibb_register_irq(struct device_node *child, struct qpnp_labibb *labibb) { - int rc = 0; - - if (is_lab_vreg_ok_irq_available(labibb)) { - rc = of_irq_get_byname(child, "lab-vreg-ok"); - if (rc < 0) { - pr_err("Invalid lab-vreg-ok irq\n"); - return rc; - } - labibb->lab_vreg.lab_vreg_ok_irq = rc; + labibb->ibb_vreg_irq = + of_irq_get_byname(child, "ibb_vreg_not_ok_interrupt"); + if (!labibb->ibb_vreg_irq) { + pr_err("Invalid ibb_vreg_not_ok_interrupt irq\n"); + return -EINVAL; } - labibb->lab_vreg.lab_sc_irq = -EINVAL; - rc = of_irq_get_byname(child, "lab-sc-err"); - if (rc < 0) - pr_debug("Unable to get lab-sc-err, rc = %d\n", rc); - else - labibb->lab_vreg.lab_sc_irq = rc; - return 0; } +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ -static int qpnp_ibb_register_irq(struct device_node *child, +static int qpnp_lab_register_irq(struct device_node *child, struct qpnp_labibb *labibb) { - int rc; - - labibb->ibb_vreg.ibb_sc_irq = -EINVAL; - rc = of_irq_get_byname(child, "ibb-sc-err"); - if (rc < 0) - pr_debug("Unable to get ibb-sc-err, rc = %d\n", rc); - else - labibb->ibb_vreg.ibb_sc_irq = rc; - + if (is_lab_vreg_ok_irq_available(labibb)) { + labibb->lab_vreg.lab_vreg_ok_irq = + of_irq_get_byname(child, "lab-vreg-ok"); + if (labibb->lab_vreg.lab_vreg_ok_irq < 0) { + pr_err("Invalid lab-vreg-ok irq\n"); + return -EINVAL; + } + } +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + labibb->lab_vreg_irq = + of_irq_get_byname(child, "lab_vreg_not_ok_interrupt"); + if (!labibb->lab_vreg_irq) { + pr_err("Invalid lab_vreg_not_ok_interrupt irq\n"); + return -EINVAL; + } +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ return 0; } @@ -3959,6 +4605,121 @@ static int qpnp_labibb_check_ttw_supported(struct qpnp_labibb *labibb) return rc; } +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +static irqreturn_t lab_vreg_handler(int irq, void *_chip) +{ + u8 val; + int rc; + struct qpnp_labibb *labibb = _chip; + + labibb_vreg_check.ocp_lab_detected = true; + pr_err("%s: LAB VREG_NG interrupt!\n", __func__); + qpnp_labibb_interrupt_disable_ctl(labibb); + + if (!labibb->lab_vreg.vreg_enabled) { + pr_err("%s: false detection display is off\n", __func__); + goto exit; + } + + /* lab status1 */ + rc = qpnp_labibb_read(labibb, + labibb->lab_base + REG_LAB_STATUS1, + &val, + 1); + if (rc) { + pr_err("%s: read register %x failed rc = %d\n", + __func__, REG_LAB_STATUS1, rc); + goto exit; + } + + if (!(val & LAB_STATUS1_VREG_OK)) { + pr_err("%s: LAB VREG NG!!!\n", __func__); + } else { + labibb_vreg_check.ocp_lab_detected = false; + goto false_detection; + } + + /* start vreg check */ + if (labibb_vreg_check.vreg_check_working) + goto exit; + + labibb_vreg_check.vreg_check_working = true; + labibb_vreg_check.current_chatter_cnt = CHATTER_CNT_START; + schedule_delayed_work(&labibb_vreg_check.vreg_check_work, + msecs_to_jiffies( + labibb_vreg_check.target_chatter_check_interval)); + goto exit; + +false_detection: + rc = qpnp_labibb_interrupt_enable_ctl(labibb, VREG_WORKER_PASSIVE); + if (rc) + pr_err("%s: qpnp_labibb_interrupt_enable_ctl error\n", + __func__); +exit: + return IRQ_HANDLED; +} + +static irqreturn_t ibb_vreg_handler(int irq, void *_chip) +{ + u8 val; + int rc; + struct qpnp_labibb *labibb = _chip; + + labibb_vreg_check.ocp_ibb_detected = true; + pr_err("%s: IBB VREG_NG interrupt!\n", __func__); + qpnp_labibb_interrupt_disable_ctl(labibb); + + if (!labibb->ibb_vreg.vreg_enabled) { + pr_err("%s: false detection display is off\n", __func__); + goto exit; + } + + /* ibb status1 */ + rc = qpnp_labibb_read(labibb, + labibb->ibb_base + REG_IBB_STATUS1, + &val, + 1); + if (rc) { + pr_err("%s: read register %x failed rc = %d\n", + __func__, REG_IBB_STATUS1, rc); + goto exit; + } + + if (!(val & IBB_STATUS1_VREG_OK)) { + pr_err("%s: IBB VREG NG!!!\n", __func__); + } else { + labibb_vreg_check.ocp_ibb_detected = false; + goto false_detection; + } + + /* start vreg check */ + if (labibb_vreg_check.vreg_check_working) + goto exit; + + labibb_vreg_check.vreg_check_working = true; + labibb_vreg_check.current_chatter_cnt = CHATTER_CNT_START; + schedule_delayed_work(&labibb_vreg_check.vreg_check_work, + msecs_to_jiffies( + labibb_vreg_check.target_chatter_check_interval)); + goto exit; + +false_detection: + rc = qpnp_labibb_interrupt_enable_ctl(labibb, VREG_WORKER_PASSIVE); + if (rc) + pr_err("%s: qpnp_labibb_interrupt_enable_ctl error\n", + __func__); + +exit: + return IRQ_HANDLED; +} + +bool qpnp_labibb_ocp_check(void) +{ + return (labibb_vreg_check.ocp_lab_detected || labibb_vreg_check.ocp_ibb_detected); +} + +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ + static int qpnp_labibb_regulator_probe(struct platform_device *pdev) { struct qpnp_labibb *labibb; @@ -4029,6 +4790,31 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) } } +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + /* initialize labibb_vreg_status_ctrl */ + labibb_vreg_check.labibb = labibb; + labibb_vreg_check.current_chatter_cnt = 0; + labibb_vreg_check.vreg_check_working = false; + labibb_vreg_check.target_chatter_cnt = DEFAULT_TARGET_CHATTER_CNT; + rc = of_property_read_u32(labibb->dev->of_node, + "somc,vreg-target-chatter-cnt", + &(labibb_vreg_check.target_chatter_cnt)); + if (rc) + pr_info("qpnp_labibb: Target chatter count sets default.\n"); + + labibb_vreg_check.target_chatter_check_interval + = DEFAULT_TARGET_CHATTER_INTERVAL; + rc = of_property_read_u32(labibb->dev->of_node, + "somc,vreg-target-chatter-interval", + &(labibb_vreg_check.target_chatter_check_interval)); + if (rc) + pr_info("qpnp_labibb: Target chatter interval sets default.\n"); + + /* initialize vreg_check_worker */ + INIT_DELAYED_WORK(&labibb_vreg_check.vreg_check_work, + vreg_check_worker); +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ + labibb->standalone = of_property_read_bool(labibb->dev->of_node, "qcom,labibb-standalone"); @@ -4118,7 +4904,14 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) case QPNP_IBB_TYPE: labibb->ibb_base = base; labibb->ibb_dig_major = revision; - qpnp_ibb_register_irq(child, labibb); +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + rc = qpnp_ibb_register_irq(child, labibb); + if (rc) { + pr_err("Failed to register IBB IRQ rc=%d\n", + rc); + goto fail_registration; + } +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ rc = register_qpnp_ibb_regulator(labibb, child); if (rc < 0) goto fail_registration; @@ -4142,11 +4935,6 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) } INIT_WORK(&labibb->lab_vreg_ok_work, qpnp_lab_vreg_notifier_work); - INIT_DELAYED_WORK(&labibb->sc_err_recovery_work, - labibb_sc_err_recovery_work); - hrtimer_init(&labibb->sc_err_check_timer, - CLOCK_MONOTONIC, HRTIMER_MODE_REL); - labibb->sc_err_check_timer.function = labibb_check_sc_err_count; dev_set_drvdata(&pdev->dev, labibb); pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d swire_control=%d\n", labibb->lab_vreg.vreg_enabled, @@ -4160,7 +4948,12 @@ fail_registration: regulator_unregister(labibb->lab_vreg.rdev); if (labibb->ibb_vreg.rdev) regulator_unregister(labibb->ibb_vreg.rdev); - +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + if (labibb->lab_vreg_irq) + free_irq(labibb->lab_vreg_irq, labibb); + if (labibb->ibb_vreg_irq) + free_irq(labibb->ibb_vreg_irq, labibb); +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ return rc; } @@ -4187,6 +4980,13 @@ static int qpnp_labibb_regulator_remove(struct platform_device *pdev) regulator_unregister(labibb->ibb_vreg.rdev); cancel_work_sync(&labibb->lab_vreg_ok_work); +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED + if (labibb->lab_vreg_irq) + free_irq(labibb->lab_vreg_irq, labibb); + if (labibb->ibb_vreg_irq) + free_irq(labibb->ibb_vreg_irq, labibb); + cancel_delayed_work_sync(&labibb_vreg_check.vreg_check_work); +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ } return 0; } diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index 27f2d9851c2a30f0492343eda9781af18dbdf3b7..724e8a4c00da9d7e506c7956c3f2b44c8fe75dd3 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -147,8 +147,6 @@ #define MIN_SOFT_START_US 0 #define MAX_SOFT_START_US 2000 -#define BST_HEADROOM_DEFAULT_MV 200 - struct ldo_regulator { struct regulator_desc rdesc; struct regulator_dev *rdev; @@ -189,7 +187,6 @@ struct bst_params { int soft_start_us; int vreg_ok_dbc_us; int voltage_mv; - u16 headroom_mv; }; struct qpnp_lcdb { @@ -856,40 +853,28 @@ irq_handled: #define VOLTAGE_STEP_50_MV 50 #define VOLTAGE_STEP_50MV_OFFSET 0xA static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb, - int voltage_mv, u8 type) + int voltage_mv) { int rc = 0; u8 val = 0; - int bst_voltage_mv; - struct ldo_regulator *ldo = &lcdb->ldo; - struct ncp_regulator *ncp = &lcdb->ncp; - struct bst_params *bst = &lcdb->bst; - - /* Vout_Boost = headroom_mv + max( Vout_LDO, abs (Vout_NCP)) */ - bst_voltage_mv = max(voltage_mv, max(ldo->voltage_mv, ncp->voltage_mv)); - bst_voltage_mv += bst->headroom_mv; - - if (bst_voltage_mv < MIN_BST_VOLTAGE_MV) - bst_voltage_mv = MIN_BST_VOLTAGE_MV; - else if (bst_voltage_mv > MAX_BST_VOLTAGE_MV) - bst_voltage_mv = MAX_BST_VOLTAGE_MV; - - if (bst_voltage_mv != bst->voltage_mv) { - val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV, - VOLTAGE_STEP_50_MV); - rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + - LCDB_BST_OUTPUT_VOLTAGE_REG, - SET_OUTPUT_VOLTAGE_MASK, val); - if (rc < 0) { - pr_err("Failed to set boost voltage %d mv rc=%d\n", - bst_voltage_mv, rc); - } else { - pr_debug("Boost voltage set = %d mv (0x%02x = 0x%02x)\n", - bst_voltage_mv, LCDB_BST_OUTPUT_VOLTAGE_REG, val); - bst->voltage_mv = bst_voltage_mv; - } - } + if (voltage_mv < MIN_BST_VOLTAGE_MV) + voltage_mv = MIN_BST_VOLTAGE_MV; + else if (voltage_mv > MAX_BST_VOLTAGE_MV) + voltage_mv = MAX_BST_VOLTAGE_MV; + + val = DIV_ROUND_UP(voltage_mv - MIN_BST_VOLTAGE_MV, + VOLTAGE_STEP_50_MV); + + rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + + LCDB_BST_OUTPUT_VOLTAGE_REG, + SET_OUTPUT_VOLTAGE_MASK, val); + if (rc < 0) + pr_err("Failed to set boost voltage %d mv rc=%d\n", + voltage_mv, rc); + else + pr_debug("Boost voltage set = %d mv (0x%02x = 0x%02x)\n", + voltage_mv, LCDB_BST_OUTPUT_VOLTAGE_REG, val); return rc; } @@ -920,16 +905,25 @@ static int qpnp_lcdb_set_voltage(struct qpnp_lcdb *lcdb, u16 offset = LCDB_LDO_OUTPUT_VOLTAGE_REG; u8 val = 0; + if (type == BST) + return qpnp_lcdb_set_bst_voltage(lcdb, voltage_mv); + + if (type == NCP) + offset = LCDB_NCP_OUTPUT_VOLTAGE_REG; + if (!is_between(voltage_mv, MIN_VOLTAGE_MV, MAX_VOLTAGE_MV)) { pr_err("Invalid voltage %dmv (min=%d max=%d)\n", voltage_mv, MIN_VOLTAGE_MV, MAX_VOLTAGE_MV); return -EINVAL; } - rc = qpnp_lcdb_set_bst_voltage(lcdb, voltage_mv, type); - if (rc < 0) { - pr_err("Failed to set boost voltage rc=%d\n", rc); - return rc; + /* Change the BST voltage to LDO + 100mV */ + if (type == LDO) { + rc = qpnp_lcdb_set_bst_voltage(lcdb, voltage_mv + 100); + if (rc < 0) { + pr_err("Failed to set boost voltage rc=%d\n", rc); + return rc; + } } /* Below logic is only valid for LDO and NCP type */ @@ -942,9 +936,6 @@ static int qpnp_lcdb_set_voltage(struct qpnp_lcdb *lcdb, val += VOLTAGE_STEP_50MV_OFFSET; } - if (type == NCP) - offset = LCDB_NCP_OUTPUT_VOLTAGE_REG; - rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + offset, SET_OUTPUT_VOLTAGE_MASK, val); if (rc < 0) @@ -1067,8 +1058,6 @@ static int qpnp_lcdb_ldo_regulator_set_voltage(struct regulator_dev *rdev, rc = qpnp_lcdb_set_voltage(lcdb, min_uV / 1000, LDO); if (rc < 0) pr_err("Failed to set LDO voltage rc=%c\n", rc); - else - lcdb->ldo.voltage_mv = min_uV / 1000; return rc; } @@ -1140,8 +1129,6 @@ static int qpnp_lcdb_ncp_regulator_set_voltage(struct regulator_dev *rdev, rc = qpnp_lcdb_set_voltage(lcdb, min_uV / 1000, NCP); if (rc < 0) pr_err("Failed to set LDO voltage rc=%c\n", rc); - else - lcdb->ncp.voltage_mv = min_uV / 1000; return rc; } @@ -1402,12 +1389,6 @@ static int qpnp_lcdb_bst_dt_init(struct qpnp_lcdb *lcdb) return -EINVAL; } - /* Boost head room configuration */ - of_property_read_u16(node, "qcom,bst-headroom-mv", - &lcdb->bst.headroom_mv); - if (lcdb->bst.headroom_mv < BST_HEADROOM_DEFAULT_MV) - lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV; - return 0; } @@ -1714,9 +1695,6 @@ static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb) } lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200 + 200; - if (!lcdb->bst.headroom_mv) - lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV; - return 0; } diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c index 08e991fa7db336834c346ce0e81368de3bf3349c..4767ac3b1600c4847e136682f07213e99cf55070 100644 --- a/drivers/regulator/qpnp-regulator.c +++ b/drivers/regulator/qpnp-regulator.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -350,6 +355,8 @@ struct qpnp_regulator { int ocp_count; int ocp_max_retries; int ocp_retry_delay_ms; + struct regulator_ocp_notification ocp_notification; + spinlock_t ocp_lock; int system_load; int hpm_min_load; int slew_rate; @@ -1255,6 +1262,34 @@ static int qpnp_regulator_common_enable_time(struct regulator_dev *rdev) return vreg->enable_time; } +static int qpnp_regulator_vs_register_ocp_notification( + struct regulator_dev *rdev, + struct regulator_ocp_notification *notification) +{ + unsigned long flags; + struct qpnp_regulator *vreg = rdev_get_drvdata(rdev); + + spin_lock_irqsave(&vreg->ocp_lock, flags); + if (notification) { + /* register ocp notification */ + vreg->ocp_notification = *notification; + } else { + /* unregister ocp notification */ + memset(&vreg->ocp_notification, 0, + sizeof(vreg->ocp_notification)); + } + spin_unlock_irqrestore(&vreg->ocp_lock, flags); + + if (qpnp_vreg_debug_mask & QPNP_VREG_DEBUG_OCP) { + pr_info("%s: registered ocp notification(notify=%p, ctxt=%p)\n", + vreg->rdesc.name, + vreg->ocp_notification.notify, + vreg->ocp_notification.ctxt); + } + + return 0; +} + static int qpnp_regulator_vs_clear_ocp(struct qpnp_regulator *vreg) { int rc; @@ -1328,8 +1363,14 @@ static irqreturn_t qpnp_regulator_vs_ocp_isr(int irq, void *data) schedule_delayed_work(&vreg->ocp_work, msecs_to_jiffies(vreg->ocp_retry_delay_ms) + 1); } else { + unsigned long flags; vreg_err(vreg, "OCP triggered %d times; no further retries\n", vreg->ocp_count); + spin_lock_irqsave(&vreg->ocp_lock, flags); + if (vreg->ocp_notification.notify) + vreg->ocp_notification.notify( + vreg->ocp_notification.ctxt); + spin_unlock_irqrestore(&vreg->ocp_lock, flags); } return IRQ_HANDLED; @@ -1560,6 +1601,8 @@ static struct regulator_ops qpnp_vs_ops = { .disable = qpnp_regulator_common_disable, .is_enabled = qpnp_regulator_common_is_enabled, .enable_time = qpnp_regulator_common_enable_time, + .register_ocp_notification + = qpnp_regulator_vs_register_ocp_notification, }; static struct regulator_ops qpnp_boost_ops = { @@ -2336,6 +2379,10 @@ static int qpnp_regulator_probe(struct platform_device *pdev) if (vreg->ocp_retry_delay_ms == 0) vreg->ocp_retry_delay_ms = QPNP_VS_OCP_DEFAULT_RETRY_DELAY_MS; + memset(&vreg->ocp_notification, 0, + sizeof(vreg->ocp_notification)); + spin_lock_init(&vreg->ocp_lock); + rdesc = &vreg->rdesc; rdesc->id = to_spmi_device(pdev->dev.parent)->ctrl->nr; rdesc->owner = THIS_MODULE; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 0e6aaef9a038f6bfd24a3bc5aac7f4d7502e371f..59ced8864b2f383b8c0d84e9c1d7af286596206e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3563,14 +3563,12 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) } else { buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; lpfc_els_free_data(phba, buf_ptr1); - elsiocb->context2 = NULL; } } if (elsiocb->context3) { buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; lpfc_els_free_bpl(phba, buf_ptr); - elsiocb->context3 = NULL; } lpfc_sli_release_iocbq(phba, elsiocb); return 0; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 38e90d9c2ceda022a8d6d32e3009ad8a7792c955..f5aeda8f014f9ae75494b61258b6b096b2e4d02c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5887,25 +5887,18 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) free_vfi_bmask: kfree(phba->sli4_hba.vfi_bmask); - phba->sli4_hba.vfi_bmask = NULL; free_xri_ids: kfree(phba->sli4_hba.xri_ids); - phba->sli4_hba.xri_ids = NULL; free_xri_bmask: kfree(phba->sli4_hba.xri_bmask); - phba->sli4_hba.xri_bmask = NULL; free_vpi_ids: kfree(phba->vpi_ids); - phba->vpi_ids = NULL; free_vpi_bmask: kfree(phba->vpi_bmask); - phba->vpi_bmask = NULL; free_rpi_ids: kfree(phba->sli4_hba.rpi_ids); - phba->sli4_hba.rpi_ids = NULL; free_rpi_bmask: kfree(phba->sli4_hba.rpi_bmask); - phba->sli4_hba.rpi_bmask = NULL; err_exit: return rc; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 1f6a3b86965f73b2da048cfd80b1251b459dce93..0e59731f95ad1d11e684cf6de2eeb0f894fd4755 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2466,10 +2466,6 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) if (pkt->entry_status & RF_BUSY) res = DID_BUS_BUSY << 16; - if (pkt->entry_type == NOTIFY_ACK_TYPE && - pkt->handle == QLA_TGT_SKIP_HANDLE) - return; - sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); if (sp) { sp->done(ha, sp, res); diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index e6faa0b050d19e78e4b52cb583f1d8e5c962d474..f57d96984ae446029de39406d921f37f417d9f20 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2865,7 +2865,7 @@ static int __qlt_send_term_imm_notif(struct scsi_qla_host *vha, pkt->entry_type = NOTIFY_ACK_TYPE; pkt->entry_count = 1; - pkt->handle = QLA_TGT_SKIP_HANDLE; + pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; nack = (struct nack_to_isp *)pkt; nack->ox_id = ntfy->ox_id; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8aa202faafb5c9ad4a803954bedac1b9c1ef49ae..9b3af788376c9d8f22cac6fea8542e4233bfc2e4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2497,8 +2497,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) if (sdp->broken_fua) { sd_first_printk(KERN_NOTICE, sdkp, "Disabling FUA\n"); sdkp->DPOFUA = 0; - } else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw && - !sdkp->device->use_16_for_rw) { + } else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) { sd_first_printk(KERN_NOTICE, sdkp, "Uses READ/WRITE(6), disabling FUA\n"); sdkp->DPOFUA = 0; diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index fb2f2159c0e1908da4384bc072e9f47a1b7c6361..f884d4fc2284eef5b5904bb45af1ab3e938e5854 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -96,6 +96,13 @@ config SCSI_UFS_QCOM_ICE Select this if you have ICE supported for UFS on QCOM chipset. If unsure, say N. +config SCSI_UFS_RESTRICT_TX_LANES + bool "Restrict the number of TX lanes to 1" + default n + help + Say Y here to restrict the number of TX lanes to 1. + This will save the power consumption in exchange for + the write performance. config SCSI_UFS_TEST tristate "Universal Flash Storage host controller driver unit-tests" diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c index 0547853c4f3a511c65c6b386fdfe65852fb16bd7..337b63f3a43a4e17ac5f56dfa5d94aa8ac1e20bc 100644 --- a/drivers/scsi/ufs/ufs-debugfs.c +++ b/drivers/scsi/ufs/ufs-debugfs.c @@ -16,6 +16,11 @@ * of the driver from userspace. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include "ufs-debugfs.h" @@ -25,6 +30,7 @@ enum field_width { BYTE = 1, WORD = 2, + DWORD = 4, }; struct desc_field_offset { @@ -881,7 +887,15 @@ static int ufsdbg_dump_device_desc_show(struct seq_file *file, void *data) {"bUD0BaseOffset", 0x1A, BYTE}, {"bUDConfigPLength", 0x1B, BYTE}, {"bDeviceRTTCap", 0x1C, BYTE}, - {"wPeriodicRTCUpdate", 0x1D, WORD} + {"wPeriodicRTCUpdate", 0x1D, WORD}, + {"bUFSFeaturesSupport", 0x1F, BYTE}, + {"bFFUTimeout", 0x20, BYTE}, + {"bQueueDepth", 0x21, BYTE}, + {"wDeviceVersion", 0x22, WORD}, + {"bNumSecureWPArea", 0x24, BYTE}, + {"dPSAMaxDataSize", 0x25, DWORD}, + {"bPSAStateTimeout", 0x29, BYTE}, + {"iProductRevisionLevel", 0x2A, BYTE}, }; pm_runtime_get_sync(hba->dev); @@ -906,6 +920,12 @@ static int ufsdbg_dump_device_desc_show(struct seq_file *file, void *data) tmp->offset, tmp->name, *(u16 *)&desc_buf[tmp->offset]); + } else if (tmp->width_byte == DWORD) { + seq_printf(file, + "Device Descriptor[Byte offset 0x%x]: %s = 0x%x\n", + tmp->offset, + tmp->name, + *(u32 *)&desc_buf[tmp->offset]); } else { seq_printf(file, "Device Descriptor[offset 0x%x]: %s. Wrong Width = %d", @@ -974,6 +994,86 @@ static const struct file_operations ufsdbg_dump_device_desc = { .read = seq_read, }; +static int ufsdbg_dump_device_health_desc_show(struct seq_file *file, void *data) +{ + int err = 0; + int buff_len = QUERY_DESC_DEVICE_HEALTH_MAX_SIZE; + u8 desc_buf[QUERY_DESC_DEVICE_HEALTH_MAX_SIZE]; + struct ufs_hba *hba = (struct ufs_hba *)file->private; + + pm_runtime_get_sync(hba->dev); + err = ufshcd_read_device_health_desc(hba, desc_buf, buff_len); + pm_runtime_put_sync(hba->dev); + + if (!err) { + int i; + for (i = 0; i < QUERY_DESC_DEVICE_HEALTH_MAX_SIZE; ++i) { + seq_printf(file, "%02x", desc_buf[i]); + } + } else { + seq_printf(file, "Reading Device Health Descriptor failed. err = %d\n", + err); + } + + return err; +} + +static int ufsdbg_dump_device_health_desc_open(struct inode *inode, struct file *file) +{ + return single_open(file, + ufsdbg_dump_device_health_desc_show, inode->i_private); +} + +static const struct file_operations ufsdbg_dump_device_health_desc = { + .open = ufsdbg_dump_device_health_desc_open, + .read = seq_read, +}; + +static int ufsdbg_dump_fw_revision_show(struct seq_file *file, void *data) +{ + int err = 0; + u8 index; + u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; + u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1]; + struct ufs_hba *hba = (struct ufs_hba *)file->private; + + pm_runtime_get_sync(hba->dev); + err = ufshcd_read_device_desc(hba, desc_buf, + QUERY_DESC_DEVICE_MAX_SIZE); + if (err) { + seq_printf(file, "Reading Device Descriptor failed. err = %d\n", + err); + goto out; + } + + index = desc_buf[DEVICE_DESC_PARAM_PRODUCT_REVISION]; + memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE + 1); + err = ufshcd_read_string_desc(hba, index, str_desc_buf, + QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); + + if (err) { + seq_printf(file, "Reading String Descriptor failed. err = %d\n", + err); + } else { + seq_printf(file, "FW revision = %s\n", &str_desc_buf[QUERY_DESC_HDR_SIZE]); + } + +out: + pm_runtime_put_sync(hba->dev); + return err; +} + +static int ufsdbg_dump_fw_revision_open(struct inode *inode, struct file *file) +{ + return single_open(file, + ufsdbg_dump_fw_revision_show, inode->i_private); +} + +static const struct file_operations ufsdbg_dump_fw_revision = { + .open = ufsdbg_dump_fw_revision_open, + .read = seq_read, +}; + static int ufsdbg_power_mode_show(struct seq_file *file, void *data) { struct ufs_hba *hba = (struct ufs_hba *)file->private; @@ -1645,6 +1745,26 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba) goto err; } + hba->debugfs_files.dump_dev_health_desc = + debugfs_create_file("dump_device_health_desc", S_IRUSR, + hba->debugfs_files.debugfs_root, hba, + &ufsdbg_dump_device_health_desc); + if (!hba->debugfs_files.dump_dev_health_desc) { + dev_err(hba->dev, + "%s: NULL dump_device_health_desc file, exiting", __func__); + goto err; + } + + hba->debugfs_files.fw_revision = + debugfs_create_file("fw_revision", S_IRUSR, + hba->debugfs_files.debugfs_root, hba, + &ufsdbg_dump_fw_revision); + if (!hba->debugfs_files.fw_revision) { + dev_err(hba->dev, + "%s: NULL fw_revision file, exiting", __func__); + goto err; + } + ufsdbg_setup_fault_injection(hba); ufshcd_vops_add_debugfs(hba, hba->debugfs_files.debugfs_root); diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index 84765b17086cd2503cc4a92435eb77fdc76ca125..7d4b0c54e59ae5c883074e9a150a2d940b3f0110 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -377,6 +382,7 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, return -EINVAL; } + memset(&ice_set, 0, sizeof(ice_set)); memset(&ice_set, 0, sizeof(ice_set)); if (qcom_host->ice.vops->config_start) { diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 47106f9373713aa946e1f176f5cd31f7e40efd4c..a3757c506a474e4ec96634030dce228d69f7a846 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -11,6 +11,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -161,10 +166,12 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host) if (err) goto disable_tx_l0; +#ifndef CONFIG_SCSI_UFS_RESTRICT_TX_LANES /* The tx lane1 clk could be muxed, hence keep this optional */ if (host->tx_l1_sync_clk) ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk", host->tx_l1_sync_clk); +#endif } host->is_lane_clks_enabled = true; goto out; @@ -208,9 +215,11 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) goto out; } +#ifndef CONFIG_SCSI_UFS_RESTRICT_TX_LANES /* The tx lane1 clk could be muxed, hence keep this optional */ ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", &host->tx_l1_sync_clk); +#endif } out: return err; @@ -1507,8 +1516,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP); } - if (host->disable_lpm) - hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8; + hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8; } static void ufs_qcom_set_caps(struct ufs_hba *hba) @@ -2416,8 +2424,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, */ static int ufs_qcom_update_sec_cfg(struct ufs_hba *hba, bool restore_sec_cfg) { - int ret = 0; - u64 scm_ret = 0; + int ret = 0, scm_ret = 0; struct ufs_qcom_host *host = ufshcd_get_variant(hba); /* scm command buffer structrue */ @@ -2458,7 +2465,7 @@ static int ufs_qcom_update_sec_cfg(struct ufs_hba *hba, bool restore_sec_cfg) cbuf.device_id = UFS_TZ_DEV_ID; ret = scm_restore_sec_cfg(cbuf.device_id, cbuf.spare, &scm_ret); if (ret || scm_ret) { - dev_dbg(hba->dev, "%s: failed, ret %d scm_ret %llu\n", + dev_dbg(hba->dev, "%s: failed, ret %d scm_ret %d\n", __func__, ret, scm_ret); if (!ret) ret = scm_ret; @@ -2467,7 +2474,7 @@ static int ufs_qcom_update_sec_cfg(struct ufs_hba *hba, bool restore_sec_cfg) } out: - dev_dbg(hba->dev, "%s: ip: restore_sec_cfg %d, op: restore_sec_cfg %d, ret %d scm_ret %llu\n", + dev_dbg(hba->dev, "%s: ip: restore_sec_cfg %d, op: restore_sec_cfg %d, ret %d scm_ret %d\n", __func__, restore_sec_cfg, host->sec_cfg_updated, ret, scm_ret); return ret; } diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 460213536e147bed244f53d58c5558c1f710385b..d96e0679736beee97cffbff5a9e2590600ce8268 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef UFS_QCOM_H_ #define UFS_QCOM_H_ @@ -38,7 +43,12 @@ #define FAST 2 #define UFS_QCOM_LIMIT_NUM_LANES_RX 2 +#ifdef CONFIG_SCSI_UFS_RESTRICT_TX_LANES +#define UFS_QCOM_LIMIT_NUM_LANES_TX 1 +#else #define UFS_QCOM_LIMIT_NUM_LANES_TX 2 +#endif + #define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G3 #define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G3 #define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4 diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index e4b2c95350ef0a31dcd6f5f4404aa9f22429491c..50184f5a4a378bb04cab65a3102e73cff9596aec 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -32,6 +32,11 @@ * any damages of any kind arising from your use or distribution of * this program. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _UFS_H #define _UFS_H @@ -156,6 +161,7 @@ enum ufs_desc_max_size { QUERY_DESC_STRING_MAX_SIZE = 0xFE, QUERY_DESC_GEOMETRY_MAZ_SIZE = 0x44, QUERY_DESC_POWER_MAX_SIZE = 0x62, + QUERY_DESC_DEVICE_HEALTH_MAX_SIZE = 0x25, QUERY_DESC_RFU_MAX_SIZE = 0x00, }; @@ -208,6 +214,14 @@ enum device_desc_param { DEVICE_DESC_PARAM_UD_LEN = 0x1B, DEVICE_DESC_PARAM_RTT_CAP = 0x1C, DEVICE_DESC_PARAM_FRQ_RTC = 0x1D, + DEVICE_DESC_PARAM_FFU_SUPPORT = 0x1F, + DEVICE_DESC_PARAM_FFU_TIMEOUT = 0x20, + DEVICE_DESC_PARAM_QUEUE_DEPTH = 0x21, + DEVICE_DESC_PARAM_DEVICE_VER = 0x22, + DEVICE_DESC_PARAM_NUM_SEC_WP_AREA = 0x24, + DEVICE_DESC_PARAM_PSM_MAX_DATA_SIZE = 0x25, + DEVICE_DESC_PARAM_PSA_STATE_TIMEOUT = 0x29, + DEVICE_DESC_PARAM_PRODUCT_REVISION = 0x2A, }; /* * Logical Unit Write Protect diff --git a/drivers/scsi/ufs/ufs_quirks.c b/drivers/scsi/ufs/ufs_quirks.c index 7a501d6d7c843b23f665c74e2ba48b688e0c5458..b9818634aba1e98cc41d1473ed904b05288c3e8f 100644 --- a/drivers/scsi/ufs/ufs_quirks.c +++ b/drivers/scsi/ufs/ufs_quirks.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "ufshcd.h" #include "ufs_quirks.h" @@ -44,6 +49,14 @@ static struct ufs_card_fix ufs_fixups[] = { UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), UFS_FIX(UFS_VENDOR_HYNIX, "hC8HL1", UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), + UFS_FIX_REVISION(UFS_VENDOR_HYNIX, UFS_MODEL_HYNIX_32GB, + UFS_REVISION_HYNIX, UFS_DEVICE_QUIRK_NO_PURGE), + UFS_FIX_REVISION(UFS_VENDOR_HYNIX, UFS_MODEL_HYNIX_64GB, + UFS_REVISION_HYNIX, UFS_DEVICE_QUIRK_NO_PURGE), + UFS_FIX_REVISION(UFS_VENDOR_SAMSUNG, UFS_MODEL_SAMSUNG_64GB, + UFS_REVISION_SAMSUNG, UFS_DEVICE_QUIRK_NO_PURGE), + UFS_FIX(UFS_VENDOR_HYNIX, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_EXTEND_SYNC_LENGTH), END_FIX }; @@ -53,6 +66,7 @@ static int ufs_get_device_info(struct ufs_hba *hba, { int err; u8 model_index; + u8 revision_index; u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1]; u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; @@ -68,7 +82,11 @@ static int ufs_get_device_info(struct ufs_hba *hba, card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; + card_data->specver = desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 | + desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1]; + model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; + revision_index = desc_buf[DEVICE_DESC_PARAM_PRODUCT_REVISION]; memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE); err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, @@ -83,6 +101,22 @@ static int ufs_get_device_info(struct ufs_hba *hba, /* Null terminate the model string */ card_data->model[MAX_MODEL_LEN] = '\0'; + memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE); + err = ufshcd_read_string_desc(hba, revision_index, str_desc_buf, + QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); + if (err) + goto out; + + str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; + strlcpy(card_data->revision, (str_desc_buf + QUERY_DESC_HDR_SIZE), + min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], + MAX_REVISION_LEN)); + /* Null terminate the model string */ + card_data->model[MAX_REVISION_LEN] = '\0'; + + dev_err(hba->dev, "%s : vid=%04x, model=%s, spec ver=%04x , fw ver=%s\n", + __func__, card_data->wmanufacturerid, card_data->model, + card_data->specver, card_data->revision); out: return err; } @@ -94,10 +128,15 @@ void ufs_advertise_fixup_device(struct ufs_hba *hba) struct ufs_card_info card_data; card_data.wmanufacturerid = 0; + card_data.specver = 0; card_data.model = kmalloc(MAX_MODEL_LEN + 1, GFP_KERNEL); if (!card_data.model) goto out; + card_data.revision = kmalloc(MAX_REVISION_LEN + 1, GFP_KERNEL); + if (!card_data.revision) + goto out; + /* get device data*/ err = ufs_get_device_info(hba, &card_data); if (err) { @@ -105,16 +144,24 @@ void ufs_advertise_fixup_device(struct ufs_hba *hba) goto out; } + if (card_data.specver < UFS_PURGE_SPEC_VER) + hba->dev_quirks |= UFS_DEVICE_QUIRK_NO_PURGE; + for (f = ufs_fixups; f->quirk; f++) { /* if same wmanufacturerid */ if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && /* and same model */ (STR_PRFX_EQUAL(f->card.model, card_data.model) || - !strcmp(f->card.model, UFS_ANY_MODEL))) + !strncmp(f->card.model, UFS_ANY_MODEL, strlen(UFS_ANY_MODEL))) && + /* and same fw revision*/ + (STR_PRFX_EQUAL(f->card.revision, card_data.revision) || + !strncmp(f->card.revision, UFS_ANY_VER, strlen(UFS_ANY_VER)))) { /* update quirks */ hba->dev_quirks |= f->quirk; + } } out: kfree(card_data.model); + kfree(card_data.revision); } diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index 3102517e841c1f787f12a0850ac9a72e42ad0fd8..c03ba7b667959408d5c8c66f93eb53fcd670796b 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _UFS_QUIRKS_H_ #define _UFS_QUIRKS_H_ @@ -19,8 +24,10 @@ #define UFS_ANY_VENDOR -1 #define UFS_ANY_MODEL "ANY_MODEL" +#define UFS_ANY_VER "ANY_VER" #define MAX_MODEL_LEN 16 +#define MAX_REVISION_LEN 8 #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE @@ -30,6 +37,17 @@ #define UFS_MODEL_TOSHIBA_32GB "THGLF2G8D4KBADR" #define UFS_MODEL_TOSHIBA_64GB "THGLF2G9D8KBADG" +/* UFS SAMSUNG MODELS */ +#define UFS_MODEL_SAMSUNG_64GB "KLUCG4J1" +#define UFS_REVISION_SAMSUNG "0101" + +/* UFS SK HYNIX MODELS */ +#define UFS_MODEL_HYNIX_32GB "hB8aL1" +#define UFS_MODEL_HYNIX_64GB "hC8aL1" +#define UFS_REVISION_HYNIX "D001" + +#define UFS_PURGE_SPEC_VER 0x210 + /** * ufs_card_info - ufs device details * @wmanufacturerid: card details @@ -37,7 +55,9 @@ */ struct ufs_card_info { u16 wmanufacturerid; + u16 specver; char *model; + char *revision; }; /** @@ -57,6 +77,15 @@ struct ufs_card_fix { { \ .card.wmanufacturerid = (_vendor),\ .card.model = (_model), \ + .card.revision = (UFS_ANY_VER), \ + .quirk = (_quirk), \ + } + +#define UFS_FIX_REVISION(_vendor, _model, _revision, _quirk) \ + { \ + .card.wmanufacturerid = (_vendor),\ + .card.model = (_model), \ + .card.revision = (_revision), \ .quirk = (_quirk), \ } @@ -146,6 +175,8 @@ struct ufs_card_fix { * device would apply this 2 steps gear switch workaround. */ #define UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH (1 << 8) +#define UFS_DEVICE_QUIRK_EXTEND_SYNC_LENGTH (1 << 23) +#define UFS_DEVICE_QUIRK_NO_PURGE (1 << 24) struct ufs_hba; void ufs_advertise_fixup_device(struct ufs_hba *hba); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c23023f43d30de79a9be23f820cd8b2c5e7e7f31..671eadf384de63d4c0e1e657d2dbad181c036faf 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -36,6 +36,11 @@ * The Linux Foundation chooses to take subject only to the GPLv2 * license terms, and distributes only under these terms. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -43,6 +48,8 @@ #include #include #include +#include +#include #include "ufshcd.h" #include "ufshci.h" @@ -246,7 +253,7 @@ static u32 ufs_query_desc_max_size[] = { QUERY_DESC_RFU_MAX_SIZE, QUERY_DESC_GEOMETRY_MAZ_SIZE, QUERY_DESC_POWER_MAX_SIZE, - QUERY_DESC_RFU_MAX_SIZE, + QUERY_DESC_DEVICE_HEALTH_MAX_SIZE, }; enum { @@ -1483,7 +1490,7 @@ start: hba->clk_gating.state = REQ_CLKS_ON; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); - queue_work(hba->clk_gating.clk_gating_workq, + queue_work(hba->clk_gating.ungating_workq, &hba->clk_gating.ungate_work); /* * fall through to check if we should wait for this @@ -1751,8 +1758,7 @@ static enum hrtimer_restart ufshcd_clkgate_hrtimer_handler( struct ufs_hba *hba = container_of(timer, struct ufs_hba, clk_gating.gate_hrtimer); - queue_work(hba->clk_gating.clk_gating_workq, - &hba->clk_gating.gate_work); + schedule_work(&hba->clk_gating.gate_work); return HRTIMER_NORESTART; } @@ -1760,7 +1766,7 @@ static enum hrtimer_restart ufshcd_clkgate_hrtimer_handler( static void ufshcd_init_clk_gating(struct ufs_hba *hba) { struct ufs_clk_gating *gating = &hba->clk_gating; - char wq_name[sizeof("ufs_clk_gating_00")]; + char wq_name[sizeof("ufs_clk_ungating_00")]; hba->clk_gating.state = CLKS_ON; @@ -1789,10 +1795,9 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba) hrtimer_init(&gating->gate_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); gating->gate_hrtimer.function = ufshcd_clkgate_hrtimer_handler; - snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d", + snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_ungating_%d", hba->host->host_no); - hba->clk_gating.clk_gating_workq = - create_singlethread_workqueue(wq_name); + hba->clk_gating.ungating_workq = create_singlethread_workqueue(wq_name); gating->is_enabled = true; @@ -1856,7 +1861,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) device_remove_file(hba->dev, &hba->clk_gating.enable_attr); ufshcd_cancel_gate_work(hba); cancel_work_sync(&hba->clk_gating.ungate_work); - destroy_workqueue(hba->clk_gating.clk_gating_workq); + destroy_workqueue(hba->clk_gating.ungating_workq); } static void ufshcd_set_auto_hibern8_timer(struct ufs_hba *hba, u32 delay) @@ -3793,6 +3798,11 @@ int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size); } +int ufshcd_read_device_health_desc(struct ufs_hba *hba, u8 *buf, u32 size) +{ + return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE_HEALTH, 0, buf, size); +} + /** * ufshcd_read_string_desc - read string descriptor * @hba: pointer to adapter instance @@ -4694,6 +4704,12 @@ int ufshcd_change_power_mode(struct ufs_hba *hba, ufshcd_dme_set(hba, UIC_ARG_MIB(DME_LocalAFC0ReqTimeOutVal), DL_AFC0ReqTimeOutVal_Default); + if (hba->dev_quirks & UFS_DEVICE_QUIRK_EXTEND_SYNC_LENGTH) { + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TxHsG1SyncLength), 0x48); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TxHsG2SyncLength), 0x48); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TxHsG3SyncLength), 0x48); + } + ret = ufshcd_uic_change_pwr_mode(hba, pwr_mode->pwr_rx << 4 | pwr_mode->pwr_tx); @@ -4976,6 +4992,8 @@ static int ufshcd_link_startup(struct ufs_hba *hba) if (!ufshcd_is_ufs_dev_active(hba)) link_startup_again = true; + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_AVAILTXDATALANES), 0x1); + link_startup: do { ufshcd_vops_link_startup_notify(hba, PRE_CHANGE); @@ -7576,8 +7594,9 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie) * It will read the opcode, idn and buf_length parameters, and, put the * response in the buffer field while updating the used size in buf_length. */ -static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) +static int ufshcd_query_ioctl(struct scsi_device *dev, u8 lun, void __user *buffer) { + struct ufs_hba *hba = shost_priv(dev->host); struct ufs_ioctl_query_data *ioctl_data; int err = 0; int length = 0; @@ -7648,7 +7667,6 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) case QUERY_ATTR_IDN_ACTIVE_ICC_LVL: case QUERY_ATTR_IDN_OOO_DATA_EN: case QUERY_ATTR_IDN_BKOPS_STATUS: - case QUERY_ATTR_IDN_PURGE_STATUS: case QUERY_ATTR_IDN_MAX_DATA_IN: case QUERY_ATTR_IDN_MAX_DATA_OUT: case QUERY_ATTR_IDN_REF_CLK_FREQ: @@ -7657,12 +7675,20 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) case QUERY_ATTR_IDN_EE_CONTROL: case QUERY_ATTR_IDN_EE_STATUS: case QUERY_ATTR_IDN_SECONDS_PASSED: + case QUERY_ATTR_IDN_FFU_STATUS: index = 0; break; case QUERY_ATTR_IDN_DYN_CAP_NEEDED: case QUERY_ATTR_IDN_CORR_PRG_BLK_NUM: index = lun; break; + case QUERY_ATTR_IDN_PURGE_STATUS: + index = 0; + if (hba->dev_quirks & UFS_DEVICE_QUIRK_NO_PURGE) { + err = -EPERM; + goto out_release_mem; + } + break; default: goto out_einval; } @@ -7706,16 +7732,36 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) case QUERY_FLAG_IDN_PERMANENT_WPE: case QUERY_FLAG_IDN_PWR_ON_WPE: case QUERY_FLAG_IDN_BKOPS_EN: - case QUERY_FLAG_IDN_PURGE_ENABLE: case QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL: case QUERY_FLAG_IDN_BUSY_RTC: break; + case QUERY_FLAG_IDN_PURGE_ENABLE: + if (hba->dev_quirks & UFS_DEVICE_QUIRK_NO_PURGE) { + err = -EPERM; + goto out_release_mem; + } + break; default: goto out_einval; } err = ufshcd_query_flag_retry(hba, ioctl_data->opcode, ioctl_data->idn, &flag); break; + case UPIU_QUERY_OPCODE_SET_FLAG: + switch (ioctl_data->idn) { + case QUERY_FLAG_IDN_PURGE_ENABLE: + if (hba->dev_quirks & UFS_DEVICE_QUIRK_NO_PURGE) { + err = -EPERM; + goto out_release_mem; + } + pm_runtime_disable(&dev->sdev_gendev); + break; + default: + goto out_einval; + } + err = ufshcd_query_flag_retry(hba, ioctl_data->opcode, + ioctl_data->idn, NULL); + break; default: goto out_einval; } @@ -7746,6 +7792,7 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) data_ptr = &flag; break; case UPIU_QUERY_OPCODE_WRITE_ATTR: + case UPIU_QUERY_OPCODE_SET_FLAG: goto out_release_mem; default: goto out_einval; @@ -7776,6 +7823,92 @@ out: return err; } +static int ufshcd_write_buffer(struct ufs_hba *hba, void __user *buffer) +{ + int err = 0; + unsigned char cmd[11] = {WRITE_BUFFER, 0x0E, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + struct ufs_ioctl_write_buffer_data *ioctl_data = NULL; + struct ufs_ioctl_write_buffer_data *fw_data = NULL; + struct Scsi_Host *shost = NULL; + struct scsi_device *sdev = NULL; + unsigned char sense[SCSI_SENSE_BUFFERSIZE]; + struct scsi_sense_hdr sshdr; + + ioctl_data = kmalloc(sizeof(struct ufs_ioctl_write_buffer_data), GFP_KERNEL); + if (!ioctl_data) { + dev_err(hba->dev, "%s: Failed allocating ioctl_data\n", __func__); + err = -ENOMEM; + goto out; + } + + err = copy_from_user(ioctl_data, buffer, sizeof(struct ufs_ioctl_write_buffer_data)); + if (err) { + dev_err(hba->dev, "%s: Failed copying ioctl_data from user, err %d\n", __func__, err); + goto out; + } + + fw_data = kmalloc(sizeof(struct ufs_ioctl_write_buffer_data) + ioctl_data->buf_size, GFP_KERNEL); + if (!fw_data) { + dev_err(hba->dev, "%s: Failed allocating fw_data\n", __func__); + err = -ENOMEM; + goto out; + } + + err = copy_from_user(fw_data, buffer, sizeof(struct ufs_ioctl_write_buffer_data) + ioctl_data->buf_size); + if (err) { + dev_err(hba->dev, "%s: Failed copying fw_data from user, err %d\n", __func__, err); + goto out; + } + + cmd[6] = (ioctl_data->buf_size >> 16) & 0xff; + cmd[7] = (ioctl_data->buf_size >> 8) & 0xff; + cmd[8] = ioctl_data->buf_size & 0xff; + + shost = scsi_host_lookup(0); + if (!shost) { + dev_err(hba->dev, "%s: Failed to get scsi_host\n", __func__); + err = -ENODEV; + goto out; + } + + sdev = scsi_device_lookup(shost, 0, 0, 0); + if (!sdev) { + dev_err(hba->dev, "%s: Failed to get scsi_device\n", __func__); + err = -ENODEV; + goto out; + } + + err = scsi_execute(sdev, cmd, DMA_TO_DEVICE, fw_data->buffer, ioctl_data->buf_size, sense, 10000, 1, + REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER, NULL); + if (err) { + dev_err(hba->dev, "%s: Failed write buffer %d\n", __func__, err); + goto out; + } + + if (scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { + dev_err(hba->dev, "%s: print sense hdr\n", __func__); + scsi_print_sense_hdr(sdev, "ffu", &sshdr); + } + +out: + if (sdev) { + scsi_device_put(sdev); + } + + if (shost) { + scsi_host_put(shost); + } + + if (fw_data) { + kfree(fw_data); + } + + if (ioctl_data) { + kfree(ioctl_data); + } + return err; +} + /** * ufshcd_ioctl - ufs ioctl callback registered in scsi_host * @dev: scsi device required for per LUN queries @@ -7789,20 +7922,35 @@ static int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer) { struct ufs_hba *hba = shost_priv(dev->host); int err = 0; + struct task_struct *tsk = current; BUG_ON(!hba); if (!buffer) { - dev_err(hba->dev, "%s: User buffer is NULL!\n", __func__); + dev_err(hba->dev, "%s: User buffer is NULL! (cmd:0x%08x)\n", + __func__, cmd); + if (tsk && tsk->pid) { + dev_err(hba->dev, " pid=%d comm=%s", tsk->pid, tsk->comm); + + if (tsk->parent && tsk->parent->pid) { + dev_err(hba->dev, " ppid=%d pcomm=%s", + tsk->parent->pid, tsk->parent->comm); + } + } return -EINVAL; } switch (cmd) { case UFS_IOCTL_QUERY: pm_runtime_get_sync(hba->dev); - err = ufshcd_query_ioctl(hba, ufshcd_scsi_to_upiu_lun(dev->lun), + err = ufshcd_query_ioctl(dev, ufshcd_scsi_to_upiu_lun(dev->lun), buffer); pm_runtime_put_sync(hba->dev); break; + case UFS_IOCTL_WRITE_BUFFER: + pm_runtime_get_sync(hba->dev); + err = ufshcd_write_buffer(hba, buffer); + pm_runtime_put_sync(hba->dev); + break; default: err = -ENOIOCTLCMD; dev_dbg(hba->dev, "%s: Unsupported ioctl cmd %d\n", __func__, diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index da3ad78d340595cf1c2b607d11fb8221d1d3866d..5ffd3c3ed5c98ef27f005c369cf4c6c87e876103 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -33,6 +33,11 @@ * any damages of any kind arising from your use or distribution of * this program. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _UFSHCD_H #define _UFSHCD_H @@ -431,7 +436,7 @@ struct ufs_clk_gating { struct device_attribute enable_attr; bool is_enabled; int active_reqs; - struct workqueue_struct *clk_gating_workq; + struct workqueue_struct *ungating_workq; }; /* Hibern8 state */ @@ -559,6 +564,8 @@ struct debugfs_files { struct fault_attr fail_attr; #endif bool is_sys_suspended; + struct dentry *dump_dev_health_desc; + struct dentry *fw_revision; }; /* tag stats statistics types */ @@ -1156,6 +1163,7 @@ out: } int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size); +int ufshcd_read_device_health_desc(struct ufs_hba *hba, u8 *buf, u32 size); static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info) { diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index 602e196e924971b72d100d2a97898896efce783d..423b27d223039f14ad771dc5ec3cba19d69f6977 100644 --- a/drivers/scsi/ufs/unipro.h +++ b/drivers/scsi/ufs/unipro.h @@ -6,6 +6,11 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _UNIPRO_H_ #define _UNIPRO_H_ @@ -119,6 +124,10 @@ #define PA_STALLNOCONFIGTIME 0x15A3 #define PA_SAVECONFIGTIME 0x15A4 +#define PA_TxHsG1SyncLength 0x1552 +#define PA_TxHsG2SyncLength 0x1554 +#define PA_TxHsG3SyncLength 0x1556 + #define PA_TACTIVATE_TIME_UNIT_US 10 #define PA_HIBERN8_TIME_UNIT_US 100 diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 03a2aadf0d3cf9a33dd55d4f527a48f30d033e15..7dbbb29d24c6cf5290cd06a7a97df570a8860f18 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -533,9 +533,7 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi, { struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc); - unsigned long flags; int req_size; - int ret; BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize); @@ -563,15 +561,8 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi, req_size = sizeof(cmd->req.cmd); } - ret = virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)); - if (ret == -EIO) { - cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; - spin_lock_irqsave(&req_vq->vq_lock, flags); - virtscsi_complete_cmd(vscsi, cmd); - spin_unlock_irqrestore(&req_vq->vq_lock, flags); - } else if (ret != 0) { + if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)) != 0) return SCSI_MLQUEUE_HOST_BUSY; - } return 0; } diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index fccbdf313e08f3ec45f2c0ad2499027dc1ee6ee7..6358d1256bb1c8fab71c01a99b868a347f888e9c 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_MACH_DOVE) += dove/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_ARCH_QCOM) += qcom/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ -obj-$(CONFIG_QCOM_SCM_QCPE) += qcom/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_SOC_TI) += ti/ diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 907960cfa9d54c042ecb14deb03b0c0a32efd223..4eb68fae063b56b6352d5cf750b710b06370cc68 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -379,10 +379,6 @@ config QCOM_SCM bool "Secure Channel Manager (SCM) support" default n -config QCOM_SCM_QCPE - bool "Para-Virtualized Secure Channel Manager (SCM) support over QCPE" - default n - menuconfig QCOM_SCM_XPU bool "Qualcomm XPU configuration driver" depends on QCOM_SCM @@ -428,6 +424,13 @@ config QCOM_WATCHDOG_V2 deadlocks. It does not run during the bootup process, so it will not catch any early lockups. +config MSM_FORCE_PANIC_ON_WDOG_BARK + bool "Force Panic on watchdog bark" + depends on QCOM_WATCHDOG_V2 + help + Triggers a kernel panic for watchdog bark. This will print more + information about the current running tasks on all the cpus. + config QCOM_IRQ_HELPER bool "QCOM Irq Helper" help @@ -884,6 +887,29 @@ config MSM_RPM_STATS_LOG the low power modes that RPM enters. The drivers outputs the message via a debugfs node. +config SUBSYS_LAST_ERR_LOG + bool "support last error log for subsystems" + help + When a fatal error is encountered, few subsystems export the + error log into SMEM. This driver supports the mechanism to read + these logs and exports them to user via procfs. + If unsure, say N + +config LAST_LOGS + bool "support last logs for system" + depends on DEBUG_FS + select SECURITY_STATUS + help + When a fatal error is encountered on system, system reboots and + saves the logs in last logs memory. This driver supports the mechanism + to read these logs and exports them via debugfs. + +config SECURITY_STATUS + bool "Get security_status" + help + Gets security status by checking oemandroidboot.securityflags + parameter. + config QSEE_IPC_IRQ_BRIDGE tristate "QSEE IPC Interrupt Bridge" help diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 0bf54bedd6ea32ad72312f6bc582ed611700f98e..5acfac0c97fd30a0f599cf44b5fa53eceb9cd85a 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -62,7 +62,6 @@ CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) obj-$(CONFIG_QCOM_SCM_ERRATA) += scm-errata.o obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o -obj-$(CONFIG_QCOM_SCM_QCPE) += scm_qcpe.o obj-$(CONFIG_QCOM_SCM_XPU) += scm-xpu.o obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o obj-$(CONFIG_QCOM_MEMORY_DUMP) += memory_dump.o @@ -107,3 +106,15 @@ obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o obj-$(CONFIG_QCOM_CX_IPEAK) += cx_ipeak.o obj-$(CONFIG_MSM_CACHE_M4M_ERP64) += cache_m4m_erp64.o +obj-$(CONFIG_ARCH_MSM8998) += debug_memory.o +obj-$(CONFIG_RAMDUMP_TAGS) += board-rdtags.o +CFLAGS_board-rdtags.o := \ + -D"INFO_PRODUCT=\"$(if $(TARGET_PRODUCT),$(TARGET_PRODUCT),unknown)\"" \ + -D"INFO_VARIANT= \ + \"$(if $(TARGET_BUILD_VARIANT),$(TARGET_BUILD_VARIANT),unknown)\"" \ + -D"INFO_BUILDID= \ + \"$(if $(SEMC_SYSTEM_VERSION),$(SEMC_SYSTEM_VERSION),private)\"" +obj-$(CONFIG_SUBSYS_LAST_ERR_LOG) += last_subsys_errlog.o +obj-$(CONFIG_ARCH_MSM8998) += console_setup.o +obj-$(CONFIG_LAST_LOGS) += last_logs.o +obj-$(CONFIG_SECURITY_STATUS) += security_status.o diff --git a/drivers/soc/qcom/board-rdtags.c b/drivers/soc/qcom/board-rdtags.c new file mode 100644 index 0000000000000000000000000000000000000000..c1893ca77c3dc4efcebb56c092ad0d95593ea20e --- /dev/null +++ b/drivers/soc/qcom/board-rdtags.c @@ -0,0 +1,86 @@ +/* + * + * Author: Nilsson, Stefan 2 + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include "board-rdtags.h" +#include + +#define RDTAGS_TAG_MAGIC 0xBADFAD01 +#define NBR_OF_ELEMENTS 3 + +struct rdtags_tag_const { + const char const key[16]; + const char const value[64]; +}; + +struct rdtags_build_tags { + const unsigned int magic; + const unsigned int size; + const struct rdtags_tag_const tag_array[NBR_OF_ELEMENTS]; +}; + +static const struct rdtags_build_tags rdtags_build_info = { + RDTAGS_TAG_MAGIC, + sizeof(rdtags_build_info), + { + { + "build_product", + INFO_PRODUCT + }, + { + "build_variant", + INFO_VARIANT + }, + { + "build_id", + INFO_BUILDID + } + } +}; + +static int board_rdtags_init(int ramdump_mode) +{ + int nbr_tags = 0; + int i = 0; + + if (!ramdump_mode) { + for (i = 0; i < NBR_OF_ELEMENTS; i++) { + const char *key; + const unsigned char *value; + unsigned int size = 0; + + key = rdtags_build_info.tag_array[i].key; + value = rdtags_build_info.tag_array[i].value; + size = strnlen(value, + sizeof(rdtags_build_info.tag_array[i].value)); + if (!rdtags_add_tag(key, value, size)) + nbr_tags++; + } + + nbr_tags += dump_table_ramdump_setup(); + } + + return nbr_tags; +} + +struct rdtags_platform_data rdtags_platdata = { + .platform_init = board_rdtags_init, +}; diff --git a/drivers/soc/qcom/board-rdtags.h b/drivers/soc/qcom/board-rdtags.h new file mode 100644 index 0000000000000000000000000000000000000000..929ef9644304cf90bd1ce4f8d1bf12a3244ca16a --- /dev/null +++ b/drivers/soc/qcom/board-rdtags.h @@ -0,0 +1,23 @@ +/* + * + * Author: Nilsson, Stefan 2 + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __BOARD_RDTAGS_H_ +#define __BOARD_RDTAGS_H_ + +extern struct rdtags_platform_data rdtags_platdata; + +#endif diff --git a/drivers/soc/qcom/common_log.c b/drivers/soc/qcom/common_log.c index 11ca86a4ba41ca083398dddc17d61345496283f0..1e8744b41e4c6164147e7ffdf778877fb6c4bc8a 100644 --- a/drivers/soc/qcom/common_log.c +++ b/drivers/soc/qcom/common_log.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -257,32 +256,6 @@ static void __init register_kernel_sections(void) } } -#ifdef CONFIG_QCOM_MINIDUMP -void dump_stack_minidump(u64 sp) -{ - struct md_region ksp_entry, ktsk_entry; - u32 cpu = smp_processor_id(); - - if (sp < KIMAGE_VADDR || sp > -256UL) - sp = current_stack_pointer; - - sp &= ~(THREAD_SIZE - 1); - scnprintf(ksp_entry.name, sizeof(ksp_entry.name), "KSTACK%d", cpu); - ksp_entry.virt_addr = sp; - ksp_entry.phys_addr = virt_to_phys((uintptr_t *)sp); - ksp_entry.size = THREAD_SIZE; - if (msm_minidump_add_region(&ksp_entry)) - pr_err("Failed to add stack of cpu %d in Minidump\n", cpu); - - scnprintf(ktsk_entry.name, sizeof(ktsk_entry.name), "KTASK%d", cpu); - ktsk_entry.virt_addr = (u64)current; - ktsk_entry.phys_addr = virt_to_phys((uintptr_t *)current); - ktsk_entry.size = sizeof(struct task_struct); - if (msm_minidump_add_region(&ktsk_entry)) - pr_err("Failed to add current task %d in Minidump\n", cpu); -} -#endif - static void __init async_common_log_init(void *data, async_cookie_t cookie) { register_kernel_sections(); diff --git a/drivers/soc/qcom/console_setup.c b/drivers/soc/qcom/console_setup.c new file mode 100644 index 0000000000000000000000000000000000000000..f77bc4c8f185bf21589cb2deafae53cfdfabdb66 --- /dev/null +++ b/drivers/soc/qcom/console_setup.c @@ -0,0 +1,163 @@ +/* drivers/soc/qcom/console_setup.c + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define CONSOLE_NAME "ttyMSM" +#define CONSOLE_IX 0 +#define CONSOLE_OPTIONS "115200,n8" +#define CONSOLE_ENABLE 0x01 + +static int need_serial_console; + +static int __init setup_serial_console(char *console_flag) +{ + unsigned long val; + + if (kstrtoul(console_flag, 16, &val)) + return -EINVAL; + + if (val & CONSOLE_ENABLE) + need_serial_console = 1; + + return 0; +} + +/* +* The S1 Boot configuration TA unit can specify that the serial console +* enable flag will be passed as Kernel boot arg with tag babe09A9. +*/ +early_param("oemandroidboot.babe09a9", setup_serial_console); + +static void disable_serial_gpio(void) +{ + struct device_node *np_tx, *np_rx, *np_tx_mux, *np_rx_mux, + *np_tx_def, *np_rx_def; + struct property *pp; + static struct property gpio_function = { + .name = "function", + .value = "gpio", + .length = sizeof("gpio"), + }; + static struct property output_low = { + .name = "output-low", + .value = NULL, + .length = 0, + }; + static struct property bias_disable = { + .name = "bias-disable", + .value = NULL, + .length = 0, + }; + + np_tx = of_find_node_by_path( + "/soc/pinctrl@03400000/msm_gpio_4"); + if (!np_tx) { + pr_err("couldn't find msm_gpio_4 node\n"); + return; + } + + np_rx = of_find_node_by_path( + "/soc/pinctrl@03400000/msm_gpio_5"); + if (!np_rx) { + pr_err("couldn't find msm_gpio_5 node\n"); + goto err0; + } + + np_tx_mux = of_find_node_by_name(np_tx, "mux"); + if (!np_tx_mux) { + pr_err("couldn't find msm_gpio_4 mux node\n"); + goto err1; + } + + np_rx_mux = of_find_node_by_name(np_rx, "mux"); + if (!np_tx_mux) { + pr_err("couldn't find msm_gpio_5 mux node\n"); + goto err2; + } + + of_update_property(np_tx_mux, &gpio_function); + of_update_property(np_rx_mux, &gpio_function); + + np_tx_def = of_find_node_by_name(np_tx, "config"); + if (!np_tx_def) { + pr_err("couldn't find msm_gpio_4 config node\n"); + goto err3; + } + + np_rx_def = of_find_node_by_name(np_rx, "config"); + if (!np_rx_def) { + pr_err("couldn't find msm_gpio_5 config node\n"); + goto err4; + } + + of_add_property(np_tx_def, &output_low); + + pp = of_find_property(np_rx_def, "bias-pull-up", NULL); + if (pp) { + of_remove_property(np_rx_def, pp); + of_add_property(np_rx_def, &bias_disable); + } + of_add_property(np_rx_def, &output_low); + + of_node_put(np_rx_def); +err4: + of_node_put(np_tx_def); +err3: + of_node_put(np_rx_mux); +err2: + of_node_put(np_tx_mux); +err1: + of_node_put(np_rx); +err0: + of_node_put(np_tx); + return; +} + +static int __init init_console_setup(void) +{ + if (need_serial_console) { + pr_info("Adding %s%d as preferred console\n", + CONSOLE_NAME, CONSOLE_IX); + add_preferred_console(CONSOLE_NAME, + CONSOLE_IX, + CONSOLE_OPTIONS); + } else { + struct device_node *np; + static struct property serial_con_status = { + .name = "status", + .value = "disabled", + .length = sizeof("disabled"), + }; + + np = of_find_node_by_path("/soc/serial@0c1b0000"); + if (!np) { + pr_err("couldn't find /soc/serial@0c1b0000 node\n"); + return -EINVAL; + } + + pr_info("disabling %s node", np->full_name); + of_update_property(np, &serial_con_status); + of_node_put(np); + disable_serial_gpio(); + } + + return 0; +} +early_initcall(init_console_setup); diff --git a/drivers/soc/qcom/debug_memory.c b/drivers/soc/qcom/debug_memory.c new file mode 100644 index 0000000000000000000000000000000000000000..619201f39f26461f97713f4daa8c8f02f79231f3 --- /dev/null +++ b/drivers/soc/qcom/debug_memory.c @@ -0,0 +1,303 @@ + /* + * 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. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#include +#endif +#ifdef CONFIG_RAMDUMP_TAGS +#include +#include "board-rdtags.h" +#endif +#ifdef CONFIG_LAST_LOGS +#include +#endif + +#define RAMDUMP_MEMDESC_SIZE (256 * SZ_1K) +#define RDTAGS_MEM_SIZE (256 * SZ_1K) +#define HEADER_SIZE (4 * SZ_1K) +#define SUBSYS_ERR_LOG_SIZE ((16 * SZ_1K) + HEADER_SIZE) + +#define RDTAGS_OFFSET (RAMDUMP_MEMDESC_SIZE) +#define AMSS_LOGS_OFFSET (RAMDUMP_MEMDESC_SIZE + RDTAGS_MEM_SIZE) +#define ADSP_LOGS_OFFSET (AMSS_LOGS_OFFSET + SUBSYS_ERR_LOG_SIZE) +#ifdef CONFIG_LAST_LOGS +#define LAST_LOGS_OFFSET (768 * SZ_1K) +#endif + +static int ramdump_mode; +static unsigned long debug_mem_base; +static unsigned long debug_mem_size; + +static int __init warm_boot_setup(char *p) +{ + unsigned long res; + + if (!p || !*p) + return -EINVAL; + + if (!kstrtoul(p, 0, &res)) { + if (res == 0xC0DEDEAD || res == 0xABADBABE) + ramdump_mode = 1; + } + + pr_info("board-ramdump: boot mode detected as %s\n", + ramdump_mode ? "ramdump" : "normal"); + return 0; +} +early_param("warmboot", warm_boot_setup); + +#ifdef CONFIG_OF +static const struct of_device_id ramdump_dt[] = { + { .compatible = "qcom,debug_memory" }, + {} +}; +#endif + +static int __init ramdump_debug_memory_init(void) +{ + struct device_node *node; + uint32_t *regs = NULL; + size_t cells; + + node = of_find_matching_node(NULL, ramdump_dt); + if (!node) { + pr_err("debug region node not found\n"); + return -EINVAL; + } + + cells = of_n_addr_cells(node) + of_n_size_cells(node); + regs = kcalloc(cells, sizeof(uint32_t), GFP_KERNEL); + if (!regs) { + pr_err("Failed to allocate memory for cells\n"); + of_node_put(node); + return -ENOMEM; + } + + if (of_property_read_u32_array(node, "reg", regs, cells)) { + pr_err("unable to find base address of node in dtb\n"); + goto failed; + } + + if (cells == 4) { + debug_mem_base = (unsigned long)regs[0] << 32 | regs[1]; + debug_mem_size = (unsigned long)regs[2] << 32 | regs[3]; + } else if (cells == 2) { + debug_mem_base = regs[0]; + debug_mem_size = regs[1]; + } else { + pr_err("bad number of cells in the regs property\n"); + goto failed; + } + + pr_info("board-ramdump: Initialized debug memory at %lx-%lx\n", + debug_mem_base, debug_mem_base + debug_mem_size - 1); + of_node_put(node); + kfree(regs); + + return 0; + +failed: + of_node_put(node); + kfree(regs); + return -EINVAL; +} + +#ifdef CONFIG_RAMDUMP_MEMDESC +static struct resource ramdump_memdesc_resources[] = { + [0] = { + .name = "ramdump_memdesc", + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ramdump_memdesc_device = { + .name = "ramdump_memdesc", + .id = -1, +}; +#endif + +#ifdef CONFIG_RAMDUMP_TAGS +static struct resource rdtags_resources[] = { + [0] = { + .name = "rdtags_mem", + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device rdtags_device = { + .name = "rdtags", + .id = -1, + .dev = { + .platform_data = &rdtags_platdata, + }, +}; +#endif + +#ifdef CONFIG_SUBSYS_LAST_ERR_LOG +static struct resource last_subsyslog_resources[] = { + [0] = { + .name = "amsslog", + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "adsplog", + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device last_subsyslog_device = { + .name = "last_subsyslog", + .id = -1, +}; +#endif + +#ifdef CONFIG_LAST_LOGS +static struct platform_device last_logs_device = { + .name = "rd_last_logs", + .id = -1, +}; + +static struct resource *last_logs_resources; +#endif + +static void __init ramdump_add_devices(void) +{ + if (!debug_mem_base) + return; + +#ifdef CONFIG_RAMDUMP_MEMDESC + ramdump_memdesc_resources[0].start = debug_mem_base; + ramdump_memdesc_resources[0].end = ramdump_memdesc_resources[0].start + + RAMDUMP_MEMDESC_SIZE - 1; + ramdump_memdesc_device.num_resources = + ARRAY_SIZE(ramdump_memdesc_resources); + ramdump_memdesc_device.resource = ramdump_memdesc_resources; + ramdump_memdesc_device.dev.platform_data = &ramdump_mode; + + platform_device_register(&ramdump_memdesc_device); +#endif + +#ifdef CONFIG_RAMDUMP_TAGS + rdtags_resources[0].start = debug_mem_base + RDTAGS_OFFSET; + rdtags_resources[0].end = rdtags_resources[0].start + + RDTAGS_MEM_SIZE - 1; + rdtags_device.num_resources = ARRAY_SIZE(rdtags_resources); + rdtags_device.resource = rdtags_resources; + rdtags_platdata.ramdump_mode = ramdump_mode; + + platform_device_register(&rdtags_device); +#endif + +#ifdef CONFIG_SUBSYS_LAST_ERR_LOG + last_subsyslog_resources[0].start = debug_mem_base + AMSS_LOGS_OFFSET; + last_subsyslog_resources[0].end = last_subsyslog_resources[0].start + + SUBSYS_ERR_LOG_SIZE - 1; + + last_subsyslog_resources[1].start = debug_mem_base + ADSP_LOGS_OFFSET; + last_subsyslog_resources[1].end = last_subsyslog_resources[1].start + + SUBSYS_ERR_LOG_SIZE - 1; + + last_subsyslog_device.num_resources = + ARRAY_SIZE(last_subsyslog_resources); + last_subsyslog_device.resource = last_subsyslog_resources; + last_subsyslog_device.dev.platform_data = &ramdump_mode; + + platform_device_register(&last_subsyslog_device); +#endif +} + +#ifdef CONFIG_LAST_LOGS +static char last_logs_names[MAX_LAST_LOGS_REGIONS][MAX_NAME_LENGTH]; +#define LAST_LOGS_HEADER_SIZE sizeof(last_logs_header) +static void __init ramdump_add_last_logs_device(void) +{ + int i; + last_logs_header __iomem *last_logs_addr; + last_logs_header last_logs_hdr; + phys_addr_t last_logs_paddr; + last_logs_region *region = NULL; + + if (!debug_mem_base) + return; + + last_logs_paddr = debug_mem_base + LAST_LOGS_OFFSET; + last_logs_addr = (last_logs_header *)ioremap(last_logs_paddr, + LAST_LOGS_HEADER_SIZE); + + if (last_logs_addr->version != LAST_LOGS_VERSION || + last_logs_addr->magic != LAST_LOGS_MAGIC) { + pr_err("ERROR: %s: magic = %x, version = 0x%x\n", + __func__, last_logs_addr->magic, + last_logs_addr->version); + iounmap(last_logs_addr); + return; + } + + memcpy_fromio((void *)&last_logs_hdr, last_logs_addr, + LAST_LOGS_HEADER_SIZE); + memset_io(last_logs_addr, 0, LAST_LOGS_HEADER_SIZE); + iounmap(last_logs_addr); + + if (last_logs_hdr.num_regions > MAX_LAST_LOGS_REGIONS) + return; + + last_logs_resources = (struct resource *)kcalloc( + last_logs_hdr.num_regions, + sizeof(struct resource), GFP_KERNEL); + if (!last_logs_resources) { + pr_err("%s: Failed to allocate memory for resources\n", + __func__); + return; + } + + for (i = 0; i < last_logs_hdr.num_regions; i++) { + region = &last_logs_hdr.regions[i]; + last_logs_resources[i].name = last_logs_names[i]; + + last_logs_resources[i].start = + last_logs_paddr + region->offset; + last_logs_resources[i].end = last_logs_resources[i].start + + region->size - 1; + last_logs_resources[i].flags = IORESOURCE_MEM; + memcpy((void *)last_logs_resources[i].name, region->name, + sizeof(region->name)); + } + + last_logs_device.resource = last_logs_resources; + last_logs_device.num_resources = last_logs_hdr.num_regions; + platform_device_register(&last_logs_device); +} +#endif + +static int __init board_ramdump_init(void) +{ + ramdump_debug_memory_init(); + ramdump_add_devices(); +#ifdef CONFIG_LAST_LOGS + ramdump_add_last_logs_device(); +#endif + return 0; +} +core_initcall(board_ramdump_init); diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index f3debd14c27b9533f0629fed575cd539b6071500..e0d9f68ceef98fceeab9a19d06d9ac6f5e6b3bd6 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -2371,35 +2371,6 @@ static void dummy_tx_cmd_ch_remote_close_ack(struct glink_transport_if *if_ptr, /* intentionally left blank */ } -/** - * dummy_tx_cmd_ch_open() - dummy channel open cmd sending function - * @if_ptr: The transport to transmit on. - * @lcid: The local channel id to encode. - * @name: The channel name to encode. - * @req_xprt: The transport the core would like to migrate this channel to. - * - * Return: 0 on success or standard Linux error code. - */ -static int dummy_tx_cmd_ch_open(struct glink_transport_if *if_ptr, - uint32_t lcid, const char *name, - uint16_t req_xprt) -{ - return -EOPNOTSUPP; -} - -/** - * dummy_tx_cmd_ch_remote_open_ack() - convert a channel open ack cmd to wire - * format and transmit - * @if_ptr: The transport to transmit on. - * @rcid: The remote channel id to encode. - * @xprt_resp: The response to a transport migration request. - */ -static void dummy_tx_cmd_ch_remote_open_ack(struct glink_transport_if *if_ptr, - uint32_t rcid, uint16_t xprt_resp) -{ - /* intentionally left blank */ -} - /** * dummy_get_power_vote_ramp_time() - Dummy Power vote ramp time * @if_ptr: The transport to transmit on. @@ -4213,14 +4184,8 @@ static struct glink_core_xprt_ctx *glink_create_dummy_xprt_ctx( if_ptr->tx_cmd_remote_rx_intent_req_ack = dummy_tx_cmd_remote_rx_intent_req_ack; if_ptr->tx_cmd_set_sigs = dummy_tx_cmd_set_sigs; - if_ptr->tx_cmd_ch_open = dummy_tx_cmd_ch_open; - if_ptr->tx_cmd_ch_remote_open_ack = dummy_tx_cmd_ch_remote_open_ack; if_ptr->tx_cmd_ch_close = dummy_tx_cmd_ch_close; if_ptr->tx_cmd_ch_remote_close_ack = dummy_tx_cmd_ch_remote_close_ack; - if_ptr->tx_cmd_tracer_pkt = dummy_tx_cmd_tracer_pkt; - if_ptr->get_power_vote_ramp_time = dummy_get_power_vote_ramp_time; - if_ptr->power_vote = dummy_power_vote; - if_ptr->power_unvote = dummy_power_unvote; xprt_ptr->ops = if_ptr; xprt_ptr->log_ctx = log_ctx; diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index 042108d4035b8322996b25e7c5ed97ee0b31e151..37193bbb23b7271d33c582d4e8680a24ee23fda6 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -2242,7 +2242,6 @@ static int parse_qos_dt_params(struct device_node *node, einfo->ramp_time_us[i] = arr32[i]; rc = 0; - kfree(arr32); return rc; invalid_key: diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 2326487302fdc5c6df5aaebab8d02379ac0d32cc..d2cdf7dc726f1936b1c782fdd8f6bafc52af7d89 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "icnss: " fmt @@ -38,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -84,59 +90,35 @@ module_param(qmi_timeout, ulong, 0600); } while (0) #define icnss_pr_err(_fmt, ...) do { \ - printk("%s" pr_fmt(_fmt), KERN_ERR, ##__VA_ARGS__); \ - icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ - ##__VA_ARGS__); \ + pr_err(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \ + ##__VA_ARGS__); \ } while (0) #define icnss_pr_warn(_fmt, ...) do { \ - printk("%s" pr_fmt(_fmt), KERN_WARNING, ##__VA_ARGS__); \ - icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ - ##__VA_ARGS__); \ + pr_warn(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_string("WRN: " pr_fmt(_fmt), \ + ##__VA_ARGS__); \ } while (0) #define icnss_pr_info(_fmt, ...) do { \ - printk("%s" pr_fmt(_fmt), KERN_INFO, ##__VA_ARGS__); \ - icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ - ##__VA_ARGS__); \ + pr_info(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_string("INF: " pr_fmt(_fmt), \ + ##__VA_ARGS__); \ } while (0) -#if defined(CONFIG_DYNAMIC_DEBUG) #define icnss_pr_dbg(_fmt, ...) do { \ - pr_debug(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_string(pr_fmt(_fmt), ##__VA_ARGS__); \ + pr_debug(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_string("DBG: " pr_fmt(_fmt), \ + ##__VA_ARGS__); \ } while (0) #define icnss_pr_vdbg(_fmt, ...) do { \ - pr_debug(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_long_string(pr_fmt(_fmt), ##__VA_ARGS__); \ - } while (0) -#elif defined(DEBUG) -#define icnss_pr_dbg(_fmt, ...) do { \ - printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ - icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ - ##__VA_ARGS__); \ + pr_debug(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_long_string("DBG: " pr_fmt(_fmt), \ + ##__VA_ARGS__); \ } while (0) -#define icnss_pr_vdbg(_fmt, ...) do { \ - printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ - icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \ - ##__VA_ARGS__); \ - } while (0) -#else -#define icnss_pr_dbg(_fmt, ...) do { \ - no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ - icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ - ##__VA_ARGS__); \ - } while (0) - -#define icnss_pr_vdbg(_fmt, ...) do { \ - no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ - icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \ - ##__VA_ARGS__); \ - } while (0) -#endif - #ifdef CONFIG_ICNSS_DEBUG #define ICNSS_ASSERT(_condition) do { \ if (!(_condition)) { \ @@ -152,8 +134,6 @@ bool ignore_qmi_timeout; #define ICNSS_QMI_ASSERT() do { } while (0) #endif -#define QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED 0x77 - enum icnss_debug_quirks { HW_ALWAYS_ON, HW_DEBUG_ENABLE, @@ -268,6 +248,7 @@ struct icnss_msa_perm_list_t msa_perm_list[ICNSS_MSA_PERM_MAX] = { struct icnss_event_pd_service_down_data { bool crashed; bool fw_rejuvenate; + bool wdog_bite; }; struct icnss_driver_event { @@ -292,9 +273,9 @@ enum icnss_driver_state { ICNSS_PD_RESTART, ICNSS_MSA0_ASSIGNED, ICNSS_WLFW_EXISTS, + ICNSS_WDOG_BITE, ICNSS_SHUTDOWN_DONE, ICNSS_HOST_TRIGGERED_PDR, - ICNSS_FW_DOWN, }; struct ce_irq_list { @@ -487,6 +468,9 @@ static struct icnss_priv { u8 requesting_sub_system; u16 line_number; char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1]; + char crash_reason[SUBSYS_CRASH_REASON_LEN]; + wait_queue_head_t wlan_pdr_debug_q; + int data_ready; } *penv; #ifdef CONFIG_ICNSS_DEBUG @@ -505,10 +489,10 @@ static int icnss_assign_msa_perm(struct icnss_mem_region_info phys_addr_t addr; u32 size; u32 i = 0; - u32 source_vmids[ICNSS_MAX_VMIDS] = {0}; + u32 source_vmids[ICNSS_MAX_VMIDS]; u32 source_nelems; - u32 dest_vmids[ICNSS_MAX_VMIDS] = {0}; - u32 dest_perms[ICNSS_MAX_VMIDS] = {0}; + u32 dest_vmids[ICNSS_MAX_VMIDS]; + u32 dest_perms[ICNSS_MAX_VMIDS]; u32 dest_nelems; enum icnss_msa_perm cur_perm = mem_region->perm; struct icnss_msa_perm_list_t *new_perm_list, *old_perm_list; @@ -736,7 +720,7 @@ static int wlfw_vbatt_send_sync_msg(struct icnss_priv *priv, if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI vbatt request rejected, result:%d error:%d\n", resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } priv->stats.vbatt_resp++; @@ -1220,7 +1204,7 @@ static int wlfw_msa_mem_info_send_sync_msg(void) if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI MSA Mem info request rejected, result:%d error:%d\n", resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } @@ -1292,7 +1276,7 @@ static int wlfw_msa_ready_send_sync_msg(void) if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI MSA ready request rejected: result:%d error:%d\n", resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } penv->stats.msa_ready_resp++; @@ -1355,7 +1339,7 @@ static int wlfw_ind_register_send_sync_msg(void) if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI indication register request rejected, resut:%d error:%d\n", resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } penv->stats.ind_register_resp++; @@ -1402,9 +1386,7 @@ static int wlfw_cap_send_sync_msg(void) if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI capability request rejected, result:%d error:%d\n", resp.resp.result, resp.resp.error); - ret = -resp.resp.result; - if (resp.resp.error == QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED) - icnss_pr_err("RF card Not present"); + ret = resp.resp.result; goto out; } @@ -1487,7 +1469,7 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI mode request rejected, mode:%d result:%d error:%d\n", mode, resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } penv->stats.mode_resp++; @@ -1537,7 +1519,7 @@ static int wlfw_wlan_cfg_send_sync_msg(struct wlfw_wlan_cfg_req_msg_v01 *data) if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI config request rejected, result:%d error:%d\n", resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } penv->stats.cfg_resp++; @@ -1590,7 +1572,7 @@ static int wlfw_ini_send_sync_msg(uint8_t fw_log_mode) if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI INI request rejected, fw_log_mode:%d result:%d error:%d\n", fw_log_mode, resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } penv->stats.ini_resp++; @@ -1650,7 +1632,7 @@ static int wlfw_athdiag_read_send_sync_msg(struct icnss_priv *priv, if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI athdiag read request rejected, result:%d error:%d\n", resp->resp.result, resp->resp.error); - ret = -resp->resp.result; + ret = resp->resp.result; goto out; } @@ -1716,7 +1698,7 @@ static int wlfw_athdiag_write_send_sync_msg(struct icnss_priv *priv, if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI athdiag write request rejected, result:%d error:%d\n", resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } out: @@ -1811,7 +1793,7 @@ static int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv) if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI rejuvenate ack request rejected, result:%d error %d\n", resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } priv->stats.rejuvenate_ack_resp++; @@ -1872,7 +1854,7 @@ static int wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv *priv, if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { icnss_pr_err("QMI dynamic feature mask request rejected, result:%d error %d\n", resp.resp.result, resp.resp.error); - ret = -resp.resp.result; + ret = resp.resp.result; goto out; } @@ -1951,12 +1933,6 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, icnss_pr_dbg("Received Ind 0x%x, msg_len: %d\n", msg_id, msg_len); - if (test_bit(ICNSS_FW_DOWN, &penv->state)) { - icnss_pr_dbg("FW down, ignoring 0x%x, state: 0x%lx\n", - msg_id, penv->state); - return; - } - switch (msg_id) { case QMI_WLFW_FW_READY_IND_V01: icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_READY_IND, @@ -2003,7 +1979,6 @@ static int icnss_driver_event_server_arrive(void *data) return -ENODEV; set_bit(ICNSS_WLFW_EXISTS, &penv->state); - clear_bit(ICNSS_FW_DOWN, &penv->state); penv->wlfw_clnt = qmi_handle_create(icnss_qmi_wlfw_clnt_notify, penv); if (!penv->wlfw_clnt) { @@ -2159,7 +2134,10 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv) icnss_pm_relax(priv); - icnss_call_driver_shutdown(priv); + if (test_bit(ICNSS_WDOG_BITE, &priv->state)) { + icnss_call_driver_shutdown(priv); + clear_bit(ICNSS_WDOG_BITE, &priv->state); + } clear_bit(ICNSS_PD_RESTART, &priv->state); @@ -2309,7 +2287,8 @@ static int icnss_call_driver_remove(struct icnss_priv *priv) static int icnss_fw_crashed(struct icnss_priv *priv, struct icnss_event_pd_service_down_data *event_data) { - icnss_pr_dbg("FW crashed, state: 0x%lx\n", priv->state); + icnss_pr_dbg("FW crashed, state: 0x%lx, wdog_bite: %d\n", + priv->state, event_data->wdog_bite); set_bit(ICNSS_PD_RESTART, &priv->state); clear_bit(ICNSS_FW_READY, &priv->state); @@ -2319,9 +2298,17 @@ static int icnss_fw_crashed(struct icnss_priv *priv, if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); + if (event_data->wdog_bite) { + set_bit(ICNSS_WDOG_BITE, &priv->state); + goto out; + } + + icnss_call_driver_shutdown(priv); + if (event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); +out: return 0; } @@ -2504,8 +2491,6 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n", priv->state, notif->crashed); - set_bit(ICNSS_FW_DOWN, &priv->state); - if (notif->crashed) priv->stats.recovery.root_pd_crash++; else @@ -2520,6 +2505,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, event_data->crashed = notif->crashed; + if (notif->crashed == CRASH_STATUS_WDOG_BITE) + event_data->wdog_bite = true; + fw_down_data.crashed = !!notif->crashed; icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); @@ -2607,8 +2595,15 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, goto event_post; } + memset(priv->crash_reason, 0, sizeof(priv->crash_reason)); + snprintf(priv->crash_reason, sizeof(priv->crash_reason), + "%s %d %s 0x%lx", "PD service down, pd_state:", + *state, "state:", priv->state); + priv->data_ready = 1; + wake_up(&priv->wlan_pdr_debug_q); switch (*state) { case ROOT_PD_WDOG_BITE: + event_data->wdog_bite = true; priv->stats.recovery.root_pd_crash++; break; case ROOT_PD_SHUTDOWN: @@ -2633,7 +2628,6 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx: cause: %s\n", *state, priv->state, icnss_pdr_cause[cause]); event_post: - set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_qmi_timeout(true); clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state); @@ -2642,8 +2636,6 @@ event_post: icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); done: - if (notification == SERVREG_NOTIF_SERVICE_STATE_UP_V01) - clear_bit(ICNSS_FW_DOWN, &priv->state); return NOTIFY_OK; } @@ -3831,15 +3823,15 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) case ICNSS_WLFW_EXISTS: seq_puts(s, "WLAN FW EXISTS"); continue; + case ICNSS_WDOG_BITE: + seq_puts(s, "MODEM WDOG BITE"); + continue; case ICNSS_SHUTDOWN_DONE: seq_puts(s, "SHUTDOWN DONE"); continue; case ICNSS_HOST_TRIGGERED_PDR: seq_puts(s, "HOST TRIGGERED PDR"); continue; - case ICNSS_FW_DOWN: - seq_puts(s, "FW DOWN"); - continue; } seq_printf(s, "UNKNOWN-%d", i); @@ -4208,6 +4200,39 @@ static int icnss_regread_open(struct inode *inode, struct file *file) return single_open(file, icnss_regread_show, inode->i_private); } +static unsigned int wlan_pdr_crash_reason_poll(struct file *filp, + struct poll_table_struct *wait) +{ + unsigned int mask = 0; + struct icnss_priv *priv = filp->private_data; + + poll_wait(filp, &priv->wlan_pdr_debug_q, wait); + + if (priv->data_ready) + mask |= (POLLIN | POLLRDNORM); + + return mask; +} + +static ssize_t wlan_pdr_crash_reason_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + int r; + char buf[SUBSYS_CRASH_REASON_LEN]; + ssize_t size = 0; + struct icnss_priv *priv = filp->private_data; + + memset(buf, 0, sizeof(buf)); + r = snprintf(buf, sizeof(buf), "%s", priv->crash_reason); + size = simple_read_from_buffer(ubuf, cnt, ppos, buf, r); + if (*ppos == r) { + memset(priv->crash_reason, 0, sizeof(priv->crash_reason)); + priv->data_ready = 0; + } + + return size; +} + static const struct file_operations icnss_regread_fops = { .read = seq_read, .write = icnss_regread_write, @@ -4216,6 +4241,30 @@ static const struct file_operations icnss_regread_fops = { .llseek = seq_lseek, }; +static const struct file_operations wlan_pdr_crash_reason_fops = { + .open = simple_open, + .read = wlan_pdr_crash_reason_read, + .poll = wlan_pdr_crash_reason_poll, + .llseek = default_llseek, +}; + +static void wlan_pdr_debugfs_create(struct dentry *root_dentry, + struct icnss_priv *priv) +{ + struct dentry *crash_reason_dentry; + + crash_reason_dentry = debugfs_create_dir("crash_reason", + root_dentry); + if (IS_ERR(crash_reason_dentry)) + icnss_pr_err("Unable to create debugfs %ld\n", + PTR_ERR(crash_reason_dentry)); + else + debugfs_create_file("wlan_pdr_crash_reason", S_IRUGO | S_IWUSR, + crash_reason_dentry, priv, + &wlan_pdr_crash_reason_fops); + +} + #ifdef CONFIG_ICNSS_DEBUG static int icnss_debugfs_create(struct icnss_priv *priv) { @@ -4241,6 +4290,7 @@ static int icnss_debugfs_create(struct icnss_priv *priv) &icnss_regread_fops); debugfs_create_file("reg_write", 0600, root_dentry, priv, &icnss_regwrite_fops); + wlan_pdr_debugfs_create(root_dentry); out: return ret; @@ -4263,6 +4313,8 @@ static int icnss_debugfs_create(struct icnss_priv *priv) debugfs_create_file("stats", 0600, root_dentry, priv, &icnss_stats_fops); + wlan_pdr_debugfs_create(root_dentry, priv); + return 0; } #endif @@ -4487,6 +4539,7 @@ static int icnss_probe(struct platform_device *pdev) goto out_smmu_deinit; } + init_waitqueue_head(&priv->wlan_pdr_debug_q); INIT_WORK(&priv->event_work, icnss_driver_event_work); INIT_WORK(&priv->qmi_recv_msg_work, icnss_qmi_wlfw_clnt_notify_work); INIT_LIST_HEAD(&priv->event_list); diff --git a/drivers/soc/qcom/ipc_router_glink_xprt.c b/drivers/soc/qcom/ipc_router_glink_xprt.c index 0c588c586306a1624d6d9e22229625717047d18f..7dd1683881fbe2428b43fb9d2f68b1c5e7d06c5b 100644 --- a/drivers/soc/qcom/ipc_router_glink_xprt.c +++ b/drivers/soc/qcom/ipc_router_glink_xprt.c @@ -82,7 +82,6 @@ struct ipc_router_glink_xprt { struct msm_ipc_router_xprt xprt; void *ch_hndl; struct workqueue_struct *xprt_wq; - struct wakeup_source notify_rxv_ws; struct rw_semaphore ss_reset_rwlock; int ss_reset; void *pil; @@ -378,7 +377,6 @@ out_read_data: glink_rx_done(glink_xprtp->ch_hndl, rx_work->iovec, reuse_intent); kfree(rx_work); up_read(&glink_xprtp->ss_reset_rwlock); - __pm_relax(&glink_xprtp->notify_rxv_ws); } static void glink_xprt_open_event(struct work_struct *work) @@ -493,8 +491,6 @@ static void glink_xprt_notify_rxv(void *handle, const void *priv, rx_work->iovec_size = size; rx_work->vbuf_provider = vbuf_provider; rx_work->pbuf_provider = pbuf_provider; - if (!glink_xprtp->dynamic_wakeup_source) - __pm_stay_awake(&glink_xprtp->notify_rxv_ws); INIT_WORK(&rx_work->work, glink_xprt_read_data); queue_work(glink_xprtp->xprt_wq, &rx_work->work); } @@ -764,7 +760,6 @@ static int ipc_router_glink_config_init( return -EFAULT; } - wakeup_source_init(&glink_xprtp->notify_rxv_ws, xprt_wq_name); mutex_lock(&glink_xprt_list_lock_lha1); list_add(&glink_xprtp->list, &glink_xprt_list); mutex_unlock(&glink_xprt_list_lock_lha1); diff --git a/drivers/soc/qcom/jtagv8-etm.c b/drivers/soc/qcom/jtagv8-etm.c index 63432e6026e2481c1bbdcd088549390517e934f9..2c15f7896c8272bd290ac0848ab61dcd81b5cb80 100644 --- a/drivers/soc/qcom/jtagv8-etm.c +++ b/drivers/soc/qcom/jtagv8-etm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -1503,7 +1503,6 @@ static int jtag_mm_etm_callback(struct notifier_block *nfb, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; - u64 version = 0; if (!etm[cpu]) goto out; @@ -1525,8 +1524,8 @@ static int jtag_mm_etm_callback(struct notifier_block *nfb, goto out; } if (etm_arch_supported(etm[cpu]->arch)) { - if (!scm_get_feat_version(TZ_DBG_ETM_FEAT_ID, &version) - && version < TZ_DBG_ETM_VER) + if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < + TZ_DBG_ETM_VER) etm[cpu]->save_restore_enabled = true; else pr_info("etm save-restore supported by TZ\n"); @@ -1616,10 +1615,8 @@ static int jtag_mm_etm_probe(struct platform_device *pdev, uint32_t cpu) mutex_lock(&etmdata->mutex); if (etmdata->init && !etmdata->enable) { if (etm_arch_supported(etmdata->arch)) { - u64 version = 0; - - if (!scm_get_feat_version(TZ_DBG_ETM_FEAT_ID, &version) - && (version < TZ_DBG_ETM_VER)) + if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < + TZ_DBG_ETM_VER) etmdata->save_restore_enabled = true; else pr_info("etm save-restore supported by TZ\n"); diff --git a/drivers/soc/qcom/jtagv8.c b/drivers/soc/qcom/jtagv8.c index f09ccce8f9c396af7c8d6ce06bf4ba23468398d6..94c391eabaea78bfdf264e5c499f02d2c9c8ba14 100644 --- a/drivers/soc/qcom/jtagv8.c +++ b/drivers/soc/qcom/jtagv8.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -974,7 +974,7 @@ static struct notifier_block jtag_cpu_pm_notifier = { static int __init msm_jtag_dbg_init(void) { int ret; - u64 version = 0; + if (msm_jtag_fuse_apps_access_disabled()) return -EPERM; @@ -982,8 +982,7 @@ static int __init msm_jtag_dbg_init(void) dbg_init_arch_data(); if (dbg_arch_supported(dbg.arch)) { - if (!scm_get_feat_version(TZ_DBG_ETM_FEAT_ID, &version) && - version < TZ_DBG_ETM_VER) { + if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER) { dbg.save_restore_enabled = true; } else { pr_info("dbg save-restore supported by TZ\n"); diff --git a/drivers/soc/qcom/last_logs.c b/drivers/soc/qcom/last_logs.c new file mode 100644 index 0000000000000000000000000000000000000000..a293c3169cc73661feb41e08e0cffca808bd2086 --- /dev/null +++ b/drivers/soc/qcom/last_logs.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct dentry *debugfs_entry; +typedef int (*func_ptr)(void *, size_t, void **, uint32_t*); + +static ssize_t last_logs_read(struct file *file, char __user *buf, + size_t len, loff_t *offp) +{ + struct last_logs_data *priv_data = + (struct last_logs_data *)file->private_data; + + return simple_read_from_buffer(buf, len, offp, + priv_data->addr, priv_data->size); +} + +static int last_logs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations last_logs_fops = { + .owner = THIS_MODULE, + .read = last_logs_read, + .open = last_logs_open, +}; + +static int last_logs_init_resource(struct platform_device *pdev, + struct resource *resource, func_ptr func) +{ + struct last_logs_data *priv_data; + size_t debug_resource_size; + int ret = -1; + void __iomem *last_virt_iobase; + void *last_logs_addr; + + debug_resource_size = resource->end - resource->start + 1; + + dev_info(&pdev->dev, "log driver initialized %u@%llx\n", + (unsigned int)debug_resource_size, resource->start); + /* + * Map address that stores the physical location diagnostic data + */ + + last_virt_iobase = devm_ioremap_nocache(&pdev->dev, resource->start, + debug_resource_size); + + if (!last_virt_iobase) { + dev_err(&pdev->dev, + "%s: ERROR could not ioremap: start=%pr, len=%u\n", + __func__, &resource->start, + (unsigned int)(debug_resource_size)); + return -ENXIO; + } + + last_logs_addr = kzalloc(debug_resource_size, GFP_KERNEL); + if (!last_logs_addr) { + pr_err("ERROR: %s could not allocate memory", __func__); + iounmap(last_virt_iobase); + return -ENOMEM; + } + + memcpy_fromio(last_logs_addr, last_virt_iobase, debug_resource_size); + /* clear & unmap last_logs debug memory */ + memset_io(last_virt_iobase, 0, debug_resource_size); + iounmap(last_virt_iobase); + + priv_data = kzalloc(sizeof(struct last_logs_data), GFP_KERNEL); + if (!priv_data) { + pr_err("ERROR: %s could not allocate memory", __func__); + kzfree(last_logs_addr); + return -ENOMEM; + } + + if (func) { + ret = (*func)(last_logs_addr, debug_resource_size, + (void **)&(priv_data->addr), (uint32_t *)&(priv_data->size)); + if (!ret) { + kzfree(last_logs_addr); + last_logs_addr = NULL; + } else if (ret) { + goto exit; + } + } else { + priv_data->addr = last_logs_addr; + priv_data->size = debug_resource_size; + } + + if (debugfs_entry) { + priv_data->debugfs_file = debugfs_create_file(resource->name, + S_IFREG | S_IRUGO, debugfs_entry, priv_data, + &last_logs_fops); + if (!priv_data->debugfs_file) { + dev_err(&pdev->dev, + "%s: Failed to create debug file entry %s\n", + __func__, resource->name); + ret = -EINVAL; + goto exit; + } + } + + return 0; + +exit: + kzfree(last_logs_addr); + kzfree(priv_data); + return ret; +} + +#define STR_TZBSP_LOG "tzbsp_log" +static int last_logs_probe(struct platform_device *pdev) +{ + int i; + + if (!debugfs_entry) { + debugfs_entry = debugfs_create_dir("last_logs", NULL); + if (!debugfs_entry) { + dev_err(&pdev->dev, + "%s: Failed to create last_logs dir\n", + __func__); + return -EINVAL; + } + } + + for (i = 0; i < pdev->num_resources; i++) { + struct resource *r = &pdev->resource[i]; + func_ptr func = NULL; + + if (!r->name) { + dev_err(&pdev->dev, "ERROR device name is invalid"); + continue; + } + +#ifdef CONFIG_MSM_TZ_LOG + if (!memcmp(r->name, STR_TZBSP_LOG, sizeof(STR_TZBSP_LOG))) + func = format_tzbsp_log; +#endif + if (last_logs_init_resource(pdev, r, func) != 0) + dev_err(&pdev->dev, "ERROR: %s last_logs_init", + r->name); + } + + return 0; +} + +static struct platform_driver last_logs_driver = { + .probe = last_logs_probe, + .driver = { + .name = "rd_last_logs", + .owner = THIS_MODULE, + }, +}; + +static int __init last_logs_init(void) +{ + return platform_driver_register(&last_logs_driver); +} + +late_initcall(last_logs_init); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("last_logs driver"); +MODULE_ALIAS("platform:last_logs"); +MODULE_AUTHOR("Dhamodharan Nallasivam "); diff --git a/drivers/soc/qcom/last_subsys_errlog.c b/drivers/soc/qcom/last_subsys_errlog.c new file mode 100644 index 0000000000000000000000000000000000000000..dd724fe4aa84d31eff1b901206697283f02858a7 --- /dev/null +++ b/drivers/soc/qcom/last_subsys_errlog.c @@ -0,0 +1,340 @@ +/* + * Author: Anirudh Madnurkar + * Author: Sandeep Kumar + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ERRLOG_SIG 0x48484814 + +enum { + SUBSYS_MODEM, + SUBSYS_ADSP, + SUBSYS_ID_MAX +}; + +struct subsys_log { + size_t log_size; + void __iomem *log_base; + char *log_buf; + u32 log_buf_len; +}; + +struct subsys_data { + char name[32]; + char resource_name[32]; + char lastlog_name[32]; + struct notifier_block notifier; + struct subsys_log subsys_log; +}; + +struct lastlog_debug_region { + u32 sig; + u32 size; + u8 data[0]; +}; + +static struct device *dev; + +static int modem_state_cb(struct notifier_block *nb, + unsigned long value, void *priv); +static int adsp_state_cb(struct notifier_block *nb, + unsigned long value, void *priv); + +static struct subsys_data subsys_data[] = { + [SUBSYS_MODEM] = { + .name = "modem", + .resource_name = "amsslog", + .lastlog_name = "last_amsslog", + .notifier = { + .notifier_call = modem_state_cb, + .priority = -INT_MAX, + }, + }, + [SUBSYS_ADSP] = { + .name = "adsp", + .resource_name = "adsplog", + .lastlog_name = "last_adsplog", + .notifier = { + .notifier_call = adsp_state_cb, + .priority = -INT_MAX, + }, + }, +}; + +static int lastlog_open(struct inode *inode, struct file *file) +{ + struct lastlog_debug_region __iomem *buffer = NULL; + struct subsys_data *subsys = PDE_DATA(inode); + struct subsys_log *subsys_log; + u32 max_size; + + if (!subsys) { + dev_err(dev, "subsystem data is NULL.\n"); + return -EINVAL; + } + + subsys_log = &subsys->subsys_log; + buffer = (struct lastlog_debug_region *)subsys_log->log_base; + if (!subsys_log->log_buf || !buffer) { + dev_err(dev, "Log buffer not initialized.\n"); + return -EINVAL; + } + + if (ERRLOG_SIG != readl_relaxed(&buffer->sig)) + return 0; + + max_size = subsys_log->log_size - (buffer->data - (uint8_t *)buffer); + memset(subsys_log->log_buf, 0x0, subsys_log->log_size); + if (readl_relaxed(&buffer->size) > max_size) + writel_relaxed(max_size, &buffer->size); + + memcpy_fromio(subsys_log->log_buf, buffer->data, buffer->size); + subsys_log->log_buf_len = readl_relaxed(&buffer->size); + return 0; +} + +static ssize_t lastlog_read(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + loff_t pos = *offset; + ssize_t count; + struct subsys_data *subsys = PDE_DATA(file_inode(file)); + struct subsys_log *subsys_log; + + if (!subsys) + return -EINVAL; + + subsys_log = &subsys->subsys_log; + if (pos >= subsys_log->log_buf_len) + return 0; + + count = min(len, (size_t)(subsys_log->log_buf_len - pos)); + if (copy_to_user(buf, subsys_log->log_buf + pos, count)) + return -EFAULT; + + *offset += count; + return count; +} + +static int lastlog_release(struct inode *inode, struct file *file) +{ + struct subsys_data *subsys = PDE_DATA(inode); + struct subsys_log *subsys_log; + + if (!subsys) + return 0; + + subsys_log = &subsys->subsys_log; + if (subsys_log->log_buf) { + memset(subsys_log->log_buf, 0x0, subsys_log->log_size); + subsys_log->log_buf_len = 0; + } + + return 0; +} + +static const struct file_operations lastlog_fops = { + .owner = THIS_MODULE, + .open = lastlog_open, + .read = lastlog_read, + .release = lastlog_release, +}; + + +static int lastlog_extract(unsigned id, + struct subsys_log *subsys_log, + char *err_str) +{ + struct lastlog_debug_region __iomem *buffer = + (struct lastlog_debug_region *)subsys_log->log_base; + char *smem_errlog = NULL; + unsigned size; + + if (!buffer) { + dev_err(dev, "Buffer in debug region not initialized.\n"); + return -EINVAL; + } + + memset_io(subsys_log->log_base, 0x0, subsys_log->log_size); + smem_errlog = smem_get_entry(id, &size, 0, SMEM_ANY_HOST_FLAG); + if (!smem_errlog) { + dev_err(dev, "Could not read SMEM ID. NULL\n"); + return -EINVAL; + } + + if (memcmp(smem_errlog, err_str, 3)) { + dev_err(dev, "SMEM error log is not starting with %s\n", + err_str); + return -EINVAL; + } + + if (size > (subsys_log->log_size - + (buffer->data - (uint8_t *)buffer))) + size = (subsys_log->log_size - + (buffer->data - (uint8_t *)buffer)); + + memcpy_toio(buffer->data, smem_errlog, size); + writel_relaxed(size, &buffer->size); + writel_relaxed(ERRLOG_SIG, &buffer->sig); + return 0; +} + +static int modem_state_cb(struct notifier_block *nb, + unsigned long value, void *priv) +{ + int ret; + + if (value == SUBSYS_RAMDUMP_NOTIFICATION || + value == SUBSYS_SOC_RESET) { + dev_info(dev, "MODEM ramdump notification received.\n"); + ret = lastlog_extract(SMEM_ERR_CRASH_LOG, + &subsys_data[SUBSYS_MODEM].subsys_log, "ERR"); + if (ret < 0) { + dev_err(dev, "Failed to extract modem error log\n"); + return NOTIFY_OK; + } + + dev_info(dev, "Modem logs extracted from smem\n"); + } + + return NOTIFY_OK; +} + +static int adsp_state_cb(struct notifier_block *nb, + unsigned long value, void *priv) +{ + int ret; + + if (value == SUBSYS_RAMDUMP_NOTIFICATION || value == SUBSYS_SOC_RESET) { + dev_info(dev, "ADSP ramdump notification received.\n"); + ret = lastlog_extract(SMEM_ERR_CRASH_LOG_ADSP, + &subsys_data[SUBSYS_ADSP].subsys_log, "err"); + if (ret < 0) { + dev_err(dev, "Failed to extract adsp error log\n"); + return NOTIFY_OK; + } + + dev_info(dev, "ADSP logs extracted from smem\n"); + } + + return NOTIFY_OK; +} + +static int lastlog_subsys_init(struct platform_device *pdev, int subsys_id) +{ + void *p, *handle; + int ret; + struct resource *res; + struct subsys_data *subsys = NULL; + struct subsys_log *subsys_log = NULL; + + subsys = &subsys_data[subsys_id]; + subsys_log = &subsys->subsys_log; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + subsys->resource_name); + if (!res || !(res->start)) { + dev_err(dev, "%s resource invalid/absent\n", + subsys->resource_name); + return -ENODEV; + } + + subsys_log->log_size = res->end - res->start + 1; + subsys_log->log_base = (char *)ioremap(res->start, + subsys_log->log_size); + if (subsys_log->log_base == NULL) { + dev_err(dev, "failed to map %s memory\n", subsys->name); + return -ENOMEM; + } + + subsys_log->log_buf = (char *)__get_free_pages(GFP_KERNEL, + get_order(subsys_log->log_size)); + if (!subsys_log->log_buf) { + dev_err(dev, "Failed to allocate pages of order %d\n", + get_order(subsys_log->log_size)); + iounmap(subsys_log->log_base); + return -ENOMEM; + } + + memset(subsys_log->log_buf, 0x0, subsys_log->log_size); + handle = subsys_notif_register_notifier(subsys->name, + &subsys->notifier); + if (IS_ERR(handle)) { + dev_err(dev, "Failed to register %s notifier\n", subsys->name); + ret = -EINVAL; + goto out; + } + + p = proc_create_data(subsys->lastlog_name, S_IRUSR, NULL, + &lastlog_fops, subsys); + if (!p) { + subsys_notif_unregister_notifier(handle, &subsys->notifier); + dev_err(dev, "failed to create %s proc entry\n", + subsys->lastlog_name); + ret = -ENOMEM; + goto out; + } + + return 0; +out: + free_pages((unsigned long)subsys_log->log_buf, + get_order(subsys_log->log_size)); + iounmap(subsys_log->log_base); + return ret; +} + +static int lastlog_subsys_driver_probe(struct platform_device *pdev) +{ + int ret, subsys_id; + + dev = &pdev->dev; + for (subsys_id = 0; subsys_id < SUBSYS_ID_MAX; subsys_id++) { + ret = lastlog_subsys_init(pdev, subsys_id); + if (ret < 0) { + dev_err(dev, "lastlogs probe failed for %s subsystem\n", + subsys_data[subsys_id].name); + return ret; + } + } + + dev_info(dev, "Last subsystem error log driver probe done.\n"); + return 0; +} + +static struct platform_driver lastlog_subsys_driver = { + .probe = lastlog_subsys_driver_probe, + .driver = { + .name = "last_subsyslog", + }, +}; + +static int __init lastlog_subsys_module_init(void) +{ + return platform_driver_register(&lastlog_subsys_driver); +} + +MODULE_AUTHOR("Anirudh Madnurkar "); +MODULE_AUTHOR("Sandeep Mantrala "); +MODULE_DESCRIPTION("subsystem error log"); +MODULE_LICENSE("GPL V2"); + +module_init(lastlog_subsys_module_init) diff --git a/drivers/soc/qcom/memory_dump_v2.c b/drivers/soc/qcom/memory_dump_v2.c index 924c826208dd93dc39d6aef5cb3c47b831c7f49d..0c38b57732815f702faf2d0808404a53697adea8 100644 --- a/drivers/soc/qcom/memory_dump_v2.c +++ b/drivers/soc/qcom/memory_dump_v2.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -21,6 +26,9 @@ #include #include #include +#ifdef CONFIG_RAMDUMP_TAGS +#include +#endif #define MSM_DUMP_TABLE_VERSION MSM_DUMP_MAKE_VERSION(2, 0) @@ -139,6 +147,22 @@ int msm_dump_data_register(enum msm_dump_table_ids id, } EXPORT_SYMBOL(msm_dump_data_register); +#ifdef CONFIG_RAMDUMP_TAGS +int dump_table_ramdump_setup(void) +{ + char data[32]; + int count; + + snprintf(data, sizeof(data), "0x%lx", + (unsigned long) memdump.table_phys); + if (rdtags_add_tag("dump_table_addr", data, + strnlen(data, sizeof(data)))) + count++; + + return count; +} +#endif + static int __init init_memory_dump(void) { struct msm_dump_table *table; diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index d82c36480159b1e0e7849356b13b7b398138e9f5..3733420d3e60564b58c26c8c1bd1cf51dc775dc2 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -43,6 +48,9 @@ #include #include "peripheral-loader.h" +#ifdef CONFIG_RAMDUMP_MEMDESC +#include +#endif #define pil_err(desc, fmt, ...) \ dev_err(desc->dev, "%s: " fmt, desc->name, ##__VA_ARGS__) @@ -56,9 +64,7 @@ #endif #define PIL_NUM_DESC 10 -#define NUM_OF_ENCRYPTED_KEY 3 static void __iomem *pil_info_base; -static void __iomem *pil_minidump_base; /** * proxy_timeout - Override for proxy vote timeouts @@ -81,18 +87,6 @@ struct pil_mdt { struct elf32_phdr phdr[]; }; -/** - * struct boot_minidump_smem_region - Representation of SMEM TOC - * @region_name: Name of modem segment to be dumped - * @region_base_address: Where segment start from - * @region_size: Size of segment to be dumped - */ -struct boot_minidump_smem_region { - char region_name[16]; - u64 region_base_address; - u64 region_size; -}; - /** * struct pil_seg - memory map representing one segment * @next: points to next seg mentor NULL if last segment @@ -147,74 +141,11 @@ struct pil_priv { phys_addr_t region_end; void *region; struct pil_image_info __iomem *info; - struct md_ssr_ss_info __iomem *minidump; - int minidump_id; int id; int unvoted_flag; size_t region_size; }; -static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev) -{ - struct boot_minidump_smem_region __iomem *region_info; - struct ramdump_segment *ramdump_segs, *s; - struct pil_priv *priv = desc->priv; - void __iomem *subsys_smem_base; - void __iomem *offset; - int ss_mdump_seg_cnt; - int ret, i; - - if (!ramdump_dev) - return -ENODEV; - - memcpy(&offset, &priv->minidump, sizeof(priv->minidump)); - offset = offset + sizeof(priv->minidump->md_ss_smem_regions_baseptr); - /* There are 3 encryption keys which also need to be dumped */ - ss_mdump_seg_cnt = readb_relaxed(offset) + - NUM_OF_ENCRYPTED_KEY; - - pr_debug("SMEM base to read minidump segments is 0x%x\n", - __raw_readl(priv->minidump)); - subsys_smem_base = ioremap(__raw_readl(priv->minidump), - ss_mdump_seg_cnt * sizeof(*region_info)); - region_info = - (struct boot_minidump_smem_region __iomem *)subsys_smem_base; - ramdump_segs = kcalloc(ss_mdump_seg_cnt, - sizeof(*ramdump_segs), GFP_KERNEL); - if (!ramdump_segs) - return -ENOMEM; - - if (desc->subsys_vmid > 0) - ret = pil_assign_mem_to_linux(desc, priv->region_start, - (priv->region_end - priv->region_start)); - - s = ramdump_segs; - for (i = 0; i < ss_mdump_seg_cnt; i++) { - memcpy(&offset, ®ion_info, sizeof(region_info)); - memcpy(&s->name, ®ion_info, sizeof(region_info)); - offset = offset + sizeof(region_info->region_name); - s->address = __raw_readl(offset); - offset = offset + sizeof(region_info->region_base_address); - s->size = __raw_readl(offset); - pr_debug("Dumping segment %s with address %pK and size 0x%x\n", - s->name, (void *)s->address, - (unsigned int)s->size); - s++; - region_info++; - } - ret = do_minidump(ramdump_dev, ramdump_segs, ss_mdump_seg_cnt); - kfree(ramdump_segs); - if (ret) - pil_err(desc, "%s: Ramdump collection failed for subsys %s rc:%d\n", - __func__, desc->name, ret); - writeb_relaxed(1, &priv->minidump->md_ss_ssr_cause); - - if (desc->subsys_vmid > 0) - ret = pil_assign_mem_to_subsys(desc, priv->region_start, - (priv->region_end - priv->region_start)); - return ret; -} - /** * pil_do_ramdump() - Ramdump an image * @desc: descriptor from pil_desc_init() @@ -223,28 +154,13 @@ static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev) * Calls the ramdump API with a list of segments generated from the addresses * that the descriptor corresponds to. */ -int pil_do_ramdump(struct pil_desc *desc, - void *ramdump_dev, void *minidump_dev) +int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev) { struct pil_priv *priv = desc->priv; struct pil_seg *seg; int count = 0, ret; struct ramdump_segment *ramdump_segs, *s; - void __iomem *offset; - memcpy(&offset, &priv->minidump, sizeof(priv->minidump)); - /* - * Collect minidump if smem base is initialized, - * ssr cause is 0. No need to check encryption status - */ - if (priv->minidump - && (__raw_readl(priv->minidump) != 0) - && (readb_relaxed(offset + sizeof(u32) + 2 * sizeof(u8)) == 0)) { - pr_debug("Dumping Minidump for %s\n", desc->name); - return pil_do_minidump(desc, minidump_dev); - - } - pr_debug("Continuing with full SSR dump for %s\n", desc->name); list_for_each_entry(seg, &priv->segs, list) count++; @@ -852,6 +768,43 @@ static int pil_parse_devicetree(struct pil_desc *desc) return 0; } +#ifdef CONFIG_RAMDUMP_MEMDESC +/* Tag the subsystem information in ramdump memory descriptors */ +static void get_mem_desc_subsys_name(const struct pil_priv *priv, + struct mem_desc *mem_desc_subsys) +{ + if (!strncmp(priv->desc->name, "modem", MEM_DESC_NAME_SIZE)) + strlcpy(mem_desc_subsys->name, "amsscore", MEM_DESC_NAME_SIZE); + else { + snprintf(mem_desc_subsys->name, MEM_DESC_NAME_SIZE, "%score", + priv->desc->name); + } +} + +static void add_mem_desc_subsys_info(const struct pil_priv *priv) +{ + struct mem_desc mem_desc_subsys; + + mem_desc_subsys.phys_addr = priv->region_start; + mem_desc_subsys.size = priv->region_end - priv->region_start; + mem_desc_subsys.flags = MEM_DESC_CORE; + get_mem_desc_subsys_name(priv, &mem_desc_subsys); + ramdump_add_mem_desc(&mem_desc_subsys); +} + +static void remove_mem_desc_subsys_info(const struct pil_priv *priv) +{ + struct mem_desc mem_desc_subsys; + + mem_desc_subsys.phys_addr = priv->region_start; + mem_desc_subsys.size = priv->region_end - priv->region_start; + mem_desc_subsys.flags = MEM_DESC_CORE; + get_mem_desc_subsys_name(priv, &mem_desc_subsys); + ramdump_remove_mem_desc(&mem_desc_subsys); +} + +#endif + /* Synchronize request_firmware() with suspend */ static DECLARE_RWSEM(pil_pm_rwsem); @@ -973,6 +926,10 @@ int pil_boot(struct pil_desc *desc) hyp_assign = true; } +#ifdef CONFIG_RAMDUMP_MEMDESC + add_mem_desc_subsys_info(priv); +#endif + trace_pil_event("before_load_seg", desc); list_for_each_entry(seg, &desc->priv->segs, list) { ret = pil_load_seg(desc, seg); @@ -1031,6 +988,9 @@ out: } if (desc->clear_fw_region && priv->region_start) pil_clear_segment(desc); +#ifdef CONFIG_RAMDUMP_MEMDESC + remove_mem_desc_subsys_info(priv); +#endif dma_free_attrs(desc->dev, priv->region_size, priv->region, priv->region_start, &desc->attrs); @@ -1066,6 +1026,10 @@ void pil_shutdown(struct pil_desc *desc) else flush_delayed_work(&priv->proxy); desc->modem_ssr = true; + +#ifdef CONFIG_RAMDUMP_MEMDESC + remove_mem_desc_subsys_info(priv); +#endif } EXPORT_SYMBOL(pil_shutdown); @@ -1106,10 +1070,9 @@ bool is_timeout_disabled(void) int pil_desc_init(struct pil_desc *desc) { struct pil_priv *priv; + int ret; void __iomem *addr; - int ret, ss_imem_offset_mdump; char buf[sizeof(priv->info->name)]; - struct device_node *ofnode = desc->dev->of_node; if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote, "Invalid proxy voting. Ignoring\n")) @@ -1132,22 +1095,6 @@ int pil_desc_init(struct pil_desc *desc) strncpy(buf, desc->name, sizeof(buf)); __iowrite32_copy(priv->info->name, buf, sizeof(buf) / 4); } - if (of_property_read_u32(ofnode, "qcom,minidump-id", - &priv->minidump_id)) - pr_debug("minidump-id not found for %s\n", desc->name); - else { - ss_imem_offset_mdump = - sizeof(struct md_ssr_ss_info) * priv->minidump_id; - if (pil_minidump_base) { - /* Add 0x4 to get start of struct md_ssr_ss_info base - * from struct md_ssr_toc for any subsystem, - * struct md_ssr_ss_info is actually the pointer - * of ToC in smem for any subsystem. - */ - addr = pil_minidump_base + ss_imem_offset_mdump + 0x4; - priv->minidump = (struct md_ssr_ss_info __iomem *)addr; - } - } ret = pil_parse_devicetree(desc); if (ret) @@ -1257,20 +1204,6 @@ static int __init msm_pil_init(void) for (i = 0; i < resource_size(&res)/sizeof(u32); i++) writel_relaxed(0, pil_info_base + (i * sizeof(u32))); - np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-minidump"); - if (!np) { - pr_warn("pil: failed to find qcom,msm-imem-minidump node\n"); - goto out; - } else { - pil_minidump_base = of_iomap(np, 0); - if (!pil_minidump_base) { - pr_err("unable to map pil minidump imem offset\n"); - goto out; - } - } - for (i = 0; i < sizeof(struct md_ssr_toc)/sizeof(u32); i++) - writel_relaxed(0, pil_minidump_base + (i * sizeof(u32))); - writel_relaxed(1, pil_minidump_base); out: return register_pm_notifier(&pil_pm_notifier); } @@ -1281,8 +1214,6 @@ static void __exit msm_pil_exit(void) unregister_pm_notifier(&pil_pm_notifier); if (pil_info_base) iounmap(pil_info_base); - if (pil_minidump_base) - iounmap(pil_minidump_base); } module_exit(msm_pil_exit); diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h index 6e74743c8c2171a04b629e7d3b8647b3364b0075..0cd2aeae1eddcfd4c45017be5ee608dac6a174cb 100644 --- a/drivers/soc/qcom/peripheral-loader.h +++ b/drivers/soc/qcom/peripheral-loader.h @@ -74,34 +74,6 @@ struct pil_image_info { __le32 size; } __attribute__((__packed__)); -#define MAX_NUM_OF_SS 3 - -/** - * struct md_ssr_ss_info - Info in imem about smem ToC - * @md_ss_smem_regions_baseptr: Start physical address of SMEM TOC - * @md_ss_num_of_regions: number of segments that need to be dumped - * @md_ss_encryption_status: status of encryption of segments - * @md_ss_ssr_cause: ssr cause enum - */ -struct md_ssr_ss_info { - u32 md_ss_smem_regions_baseptr; - u8 md_ss_num_of_regions; - u8 md_ss_encryption_status; - u8 md_ss_ssr_cause; - u8 reserved; -}; - -/** - * struct md_ssr_toc - Wrapper of struct md_ssr_ss_info - * @md_ssr_toc_init: flag to indicate to MSS SW about imem init done - * @md_ssr_ss: Instance of struct md_ssr_ss_info for a subsystem - */ -struct md_ssr_toc /* Shared IMEM ToC struct */ -{ - u32 md_ssr_toc_init; - struct md_ssr_ss_info md_ssr_ss[MAX_NUM_OF_SS]; -}; - /** * struct pil_reset_ops - PIL operations * @init_image: prepare an image for authentication @@ -134,8 +106,7 @@ extern void pil_shutdown(struct pil_desc *desc); extern void pil_free_memory(struct pil_desc *desc); extern void pil_desc_release(struct pil_desc *desc); extern phys_addr_t pil_get_entry_addr(struct pil_desc *desc); -extern int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev, - void *minidump_dev); +extern int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev); extern int pil_assign_mem_to_subsys(struct pil_desc *desc, phys_addr_t addr, size_t size); extern int pil_assign_mem_to_linux(struct pil_desc *desc, phys_addr_t addr, @@ -155,8 +126,7 @@ static inline phys_addr_t pil_get_entry_addr(struct pil_desc *desc) { return 0; } -static inline int pil_do_ramdump(struct pil_desc *desc, - void *ramdump_dev, void *minidump_dev) +static inline int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev) { return 0; } diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c index 4bea034f0bdd5ac84f98d19044e1cde9ab08ce02..5fcb0f95733c47ca49f2fcce25682e3715416417 100644 --- a/drivers/soc/qcom/pil-msa.c +++ b/drivers/soc/qcom/pil-msa.c @@ -78,8 +78,7 @@ #define MSS_MAGIC 0XAABADEAD /* CX_IPEAK Parameters */ #define CX_IPEAK_MSS BIT(5) -/* Timeout value for MBA boot when minidump is enabled */ -#define MBA_ENCRYPTION_TIMEOUT 3000 + enum scm_cmd { PAS_MEM_SETUP_CMD = 2, }; @@ -245,12 +244,7 @@ static int pil_msa_wait_for_mba_ready(struct q6v5_data *drv) struct device *dev = drv->desc.dev; int ret; u32 status; - u64 val; - - if (of_property_read_bool(dev->of_node, "qcom,minidump-id")) - pbl_mba_boot_timeout_ms = MBA_ENCRYPTION_TIMEOUT; - - val = is_timeout_disabled() ? 0 : pbl_mba_boot_timeout_ms * 1000; + u64 val = is_timeout_disabled() ? 0 : pbl_mba_boot_timeout_ms * 1000; /* Wait for PBL completion. */ ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status, diff --git a/drivers/soc/qcom/pil-msa.h b/drivers/soc/qcom/pil-msa.h index b1a5311859ffb15fe60fc5099a81ecab23d79285..896f0c7c232b52a48cbac6b50da80b64106c946e 100644 --- a/drivers/soc/qcom/pil-msa.h +++ b/drivers/soc/qcom/pil-msa.h @@ -24,7 +24,6 @@ struct modem_data { struct subsys_device *subsys; struct subsys_desc subsys_desc; void *ramdump_dev; - void *minidump_dev; bool crash_shutdown; u32 pas_id; bool ignore_errors; diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c index 45712457de73be854a23d6539418b1b4770d3a9a..a0cd5afcdaf3aeddc9807dbbbaff7ad60a0cbf20 100644 --- a/drivers/soc/qcom/pil-q6v5-mss.c +++ b/drivers/soc/qcom/pil-q6v5-mss.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -44,7 +49,7 @@ #define subsys_to_drv(d) container_of(d, struct modem_data, subsys_desc) -static void log_modem_sfr(void) +static void log_modem_sfr(struct modem_data *drv) { u32 size; char *smem_reason, reason[MAX_SSR_REASON_LEN]; @@ -61,6 +66,7 @@ static void log_modem_sfr(void) } strlcpy(reason, smem_reason, min(size, MAX_SSR_REASON_LEN)); + update_crash_reason(drv->subsys, smem_reason, size); pr_err("modem subsystem failure reason: %s.\n", reason); smem_reason[0] = '\0'; @@ -69,7 +75,7 @@ static void log_modem_sfr(void) static void restart_modem(struct modem_data *drv) { - log_modem_sfr(); + log_modem_sfr(drv); drv->ignore_errors = true; subsystem_restart_dev(drv->subsys); } @@ -171,8 +177,7 @@ static int modem_ramdump(int enable, const struct subsys_desc *subsys) if (ret) return ret; - ret = pil_do_ramdump(&drv->q6->desc, - drv->ramdump_dev, drv->minidump_dev); + ret = pil_do_ramdump(&drv->q6->desc, drv->ramdump_dev); if (ret < 0) pr_err("Unable to dump modem fw memory (rc = %d).\n", ret); @@ -231,18 +236,9 @@ static int pil_subsys_init(struct modem_data *drv, ret = -ENOMEM; goto err_ramdump; } - drv->minidump_dev = create_ramdump_device("md_modem", &pdev->dev); - if (!drv->minidump_dev) { - pr_err("%s: Unable to create a modem minidump device.\n", - __func__); - ret = -ENOMEM; - goto err_minidump; - } return 0; -err_minidump: - destroy_ramdump_device(drv->ramdump_dev); err_ramdump: subsys_unregister(drv->subsys); err_subsys: @@ -424,7 +420,6 @@ static int pil_mss_driver_exit(struct platform_device *pdev) subsys_unregister(drv->subsys); destroy_ramdump_device(drv->ramdump_dev); - destroy_ramdump_device(drv->minidump_dev); pil_desc_release(&drv->q6->desc); return 0; } diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c index 7a62c2e36da8219db0b2b2ba201298c94d6c3fff..d14e82415c5ac6f589cf375420712e07ad2edcbd 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -12,7 +12,6 @@ #define pr_fmt(fmt) "qbt1000:%s: " fmt, __func__ -#include #include #include #include @@ -106,14 +105,10 @@ struct qbt1000_drvdata { */ struct fw_ipc_cmd { uint32_t status; - uint32_t numMsgs; - uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE]; -}; - -struct fw_ipc_header { uint32_t msg_type; uint32_t msg_len; uint32_t resp_needed; + uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE]; }; /* @@ -357,14 +352,7 @@ static int qbt1000_open(struct inode *inode, struct file *file) */ static int qbt1000_release(struct inode *inode, struct file *file) { - struct qbt1000_drvdata *drvdata; - - if (!file->private_data) { - pr_err("Null pointer passed in file->private_data"); - return -EINVAL; - } - - drvdata = file->private_data; + struct qbt1000_drvdata *drvdata = file->private_data; atomic_inc(&drvdata->available); return 0; @@ -386,11 +374,6 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg) void __user *priv_arg = (void __user *)arg; struct qbt1000_drvdata *drvdata; - if (!file->private_data) { - pr_err("Null pointer passed in file->private_data"); - return -EINVAL; - } - drvdata = file->private_data; if (IS_ERR(priv_arg)) { @@ -806,8 +789,6 @@ static int qbt1000_create_input_device(struct qbt1000_drvdata *drvdata) BIT_MASK(KEY_HOMEPAGE); drvdata->in_dev->keybit[BIT_WORD(KEY_CAMERA)] |= BIT_MASK(KEY_CAMERA); - drvdata->in_dev->keybit[BIT_WORD(KEY_VOLUMEDOWN)] |= - BIT_MASK(KEY_VOLUMEDOWN); drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |= BIT_MASK(KEY_POWER); @@ -936,14 +917,11 @@ static irqreturn_t qbt1000_gpio_isr(int irq, void *dev_id) */ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id) { - uint8_t *msg_buffer; struct fw_ipc_cmd *rx_cmd; - struct fw_ipc_header *header; - int i, j; + int i; uint32_t rxipc = FP_APP_CMD_RX_IPC; struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id; int rc = 0; - uint32_t retry_count = 10; pm_stay_awake(drvdata->dev); @@ -955,25 +933,18 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id) goto end; } + pr_debug("firmware interrupt received (irq %d)\n", irq); + if (!drvdata->fp_app_handle) goto end; - while (retry_count > 0) { - /* - * send the TZ command to fetch the message from firmware - * TZ will process the message if it can - */ - rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0, - &rxipc, sizeof(rxipc), - (void *)&rx_cmd, sizeof(*rx_cmd)); - if (rc < 0) { - msleep(50); /* sleep for 50ms before retry */ - retry_count -= 1; - continue; - } else { - break; - } - } + /* + * send the TZ command to fetch the message from firmware + * TZ will process the message if it can + */ + rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0, + &rxipc, sizeof(rxipc), + (void *)&rx_cmd, sizeof(*rx_cmd)); if (rc < 0) { pr_err("failure sending tz cmd %d\n", rxipc); @@ -985,35 +956,29 @@ static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id) goto end; } - msg_buffer = rx_cmd->msg_data; - - for (j = 0; j < rx_cmd->numMsgs; j++) { - header = (struct fw_ipc_header *) msg_buffer; - /* - * given the IPC message type, search for a corresponding event - * for the driver client. If found, add to the events FIFO - */ - for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) { - if (g_msg_to_event[i].msg_type == header->msg_type) { - enum qbt1000_fw_event ev = - g_msg_to_event[i].fw_event; - struct fw_event_desc fw_ev_desc; - - mutex_lock(&drvdata->fw_events_mutex); - pr_debug("fw events: add %d\n", (int) ev); - fw_ev_desc.ev = ev; - - if (!kfifo_put(&drvdata->fw_events, fw_ev_desc)) - pr_err("fw events: fifo full, drop event %d\n", - (int) ev); - - mutex_unlock(&drvdata->fw_events_mutex); - break; - } + /* + * given the IPC message type, search for a corresponding event for the + * driver client. If found, add to the events FIFO + */ + for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) { + if (g_msg_to_event[i].msg_type == rx_cmd->msg_type) { + enum qbt1000_fw_event ev = g_msg_to_event[i].fw_event; + struct fw_event_desc fw_ev_desc; + + mutex_lock(&drvdata->fw_events_mutex); + pr_debug("fw events: add %d\n", (int) ev); + fw_ev_desc.ev = ev; + + if (!kfifo_put(&drvdata->fw_events, fw_ev_desc)) + pr_err("fw events: fifo full, drop event %d\n", + (int) ev); + + mutex_unlock(&drvdata->fw_events_mutex); + wake_up_interruptible(&drvdata->read_wait_queue); + break; } - msg_buffer += sizeof(*header) + header->msg_len; } - wake_up_interruptible(&drvdata->read_wait_queue); + end: mutex_unlock(&drvdata->mutex); pm_relax(drvdata->dev); diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c index 3791169ec0ace7dd0a53c836e004dcfedb879b95..eca992ec17e4a7e06a4f92cfd0401779804d303e 100644 --- a/drivers/soc/qcom/qdsp6v2/apr.c +++ b/drivers/soc/qcom/qdsp6v2/apr.c @@ -820,7 +820,6 @@ static void dispatch_event(unsigned long code, uint16_t proc) uint16_t clnt; int i, j; - memset(&data, 0, sizeof(data)); data.opcode = RESET_EVENTS; data.reset_event = code; diff --git a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c index 9e61ff1ebfcc5486cc91b0e7a65e160a121e1c8c..83e3775ed53380619980992b34c40f386ffdd040 100644 --- a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c +++ b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, 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 @@ -29,7 +29,6 @@ #include #include #include -#include #define MSM_AUDIO_ION_PROBED (1 << 0) @@ -179,123 +178,6 @@ err: } EXPORT_SYMBOL(msm_audio_ion_alloc); -static int msm_audio_hyp_assign(ion_phys_addr_t *paddr, size_t *pa_len, - u8 assign_type) -{ - int srcVM[1] = {VMID_HLOS}; - int destVM[1] = {VMID_CP_ADSP_SHARED}; - int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; - int ret = 0; - - switch (assign_type) { - case HLOS_TO_ADSP: - srcVM[0] = VMID_HLOS; - destVM[0] = VMID_CP_ADSP_SHARED; - break; - case ADSP_TO_HLOS: - srcVM[0] = VMID_CP_ADSP_SHARED; - destVM[0] = VMID_HLOS; - break; - default: - pr_err("%s: Invalid assign type = %d\n", __func__, assign_type); - ret = -EINVAL; - goto done; - } - - ret = hyp_assign_phys(*paddr, *pa_len, srcVM, 1, destVM, destVMperm, 1); - if (ret) - pr_err("%s: hyp_assign_phys failed for type %d, rc = %d\n", - __func__, assign_type, ret); -done: - return ret; -} - -int msm_audio_ion_phys_free(struct ion_client *client, - struct ion_handle *handle, - ion_phys_addr_t *paddr, - size_t *pa_len, u8 assign_type) -{ - int ret; - - if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) { - pr_debug("%s:probe is not done, deferred\n", __func__); - return -EPROBE_DEFER; - } - - if (!client || !handle || !paddr || !pa_len) { - pr_err("%s: Invalid params\n", __func__); - return -EINVAL; - } - - ret = ion_phys(client, handle, paddr, pa_len); - if (ret) { - pr_err("%s: could not get physical address for handle, ret = %d\n", - __func__, ret); - goto err_ion_handle; - } - - ret = msm_audio_hyp_assign(paddr, pa_len, assign_type); - -err_ion_handle: - ion_free(client, handle); - ion_client_destroy(client); - - return ret; -} - -int msm_audio_ion_phys_assign(const char *name, struct ion_client **client, - struct ion_handle **handle, int fd, - ion_phys_addr_t *paddr, - size_t *pa_len, u8 assign_type) -{ - int ret; - - if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) { - pr_debug("%s:probe is not done, deferred\n", __func__); - return -EPROBE_DEFER; - } - - if (!name || !client || !handle || !paddr || !pa_len) { - pr_err("%s: Invalid params\n", __func__); - return -EINVAL; - } - - *client = msm_audio_ion_client_create(name); - if (IS_ERR_OR_NULL((void *)(*client))) { - pr_err("%s: ION create client failed\n", __func__); - return -EINVAL; - } - - *handle = ion_import_dma_buf(*client, fd); - if (IS_ERR_OR_NULL((void *) (*handle))) { - pr_err("%s: ion import dma buffer failed\n", - __func__); - ret = -EINVAL; - goto err_destroy_client; - } - - ret = ion_phys(*client, *handle, paddr, pa_len); - if (ret) { - pr_err("%s: could not get physical address for handle, ret = %d\n", - __func__, ret); - goto err_ion_handle; - } - - ret = msm_audio_hyp_assign(paddr, pa_len, assign_type); - - return ret; - -err_ion_handle: - ion_free(*client, *handle); - -err_destroy_client: - ion_client_destroy(*client); - *client = NULL; - *handle = NULL; - - return ret; -} - int msm_audio_ion_import(const char *name, struct ion_client **client, struct ion_handle **handle, int fd, unsigned long *ionflag, size_t bufsz, diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c index 38cc8696318125922df77c39ac5a06ab2900b2db..d86f8671705a23b3b27d737ae62f8896dcdae55e 100644 --- a/drivers/soc/qcom/qpnp-haptic.c +++ b/drivers/soc/qcom/qpnp-haptic.c @@ -2233,23 +2233,13 @@ static void qpnp_hap_td_enable(struct timed_output_dev *dev, int time_ms) timed_dev); int rc; - if (time_ms < 0) + if (time_ms <= 0) return; - mutex_lock(&hap->lock); - - if (time_ms == 0) { - /* disable haptics */ - hrtimer_cancel(&hap->hap_timer); - hap->state = 0; - schedule_work(&hap->work); - mutex_unlock(&hap->lock); - return; - } - if (time_ms < 10) time_ms = 10; + mutex_lock(&hap->lock); if (is_sw_lra_auto_resonance_control(hap)) hrtimer_cancel(&hap->auto_res_err_poll_timer); diff --git a/drivers/soc/qcom/ramdump.c b/drivers/soc/qcom/ramdump.c index c8353dc8a43a38600e1d7399062f857c7df8a156..bbee60642db75713e572178f9859af9c4d4d28e0 100644 --- a/drivers/soc/qcom/ramdump.c +++ b/drivers/soc/qcom/ramdump.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -24,13 +29,12 @@ #include #include #include +#include #include #include #include #define RAMDUMP_WAIT_MSECS 120000 -#define MAX_STRTBL_SIZE 512 -#define MAX_NAME_LENGTH 16 struct ramdump_device { char name[256]; @@ -168,7 +172,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count, goto ramdump_done; } - alignbuf = kzalloc(copy_size, GFP_KERNEL); + alignbuf = vzalloc(copy_size); if (!alignbuf) { pr_err("Ramdump(%s): Unable to alloc mem for aligned buf\n", rd_dev->name); @@ -206,7 +210,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count, goto ramdump_done; } - kfree(finalbuf); + vfree(finalbuf); if (!vaddr && origdevice_mem) dma_unremap(rd_dev->device.parent, origdevice_mem, copy_size); @@ -221,7 +225,7 @@ ramdump_done: if (!vaddr && origdevice_mem) dma_unremap(rd_dev->device.parent, origdevice_mem, copy_size); - kfree(finalbuf); + vfree(finalbuf); rd_dev->data_ready = 0; *pos = 0; complete(&rd_dev->ramdump_complete); @@ -393,143 +397,12 @@ static int _do_ramdump(void *handle, struct ramdump_segment *segments, } -static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr) -{ - return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff); -} - -static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx) -{ - return &elf_sheader(hdr)[idx]; -} - -static inline char *elf_str_table(struct elfhdr *hdr) -{ - if (hdr->e_shstrndx == SHN_UNDEF) - return NULL; - return (char *)hdr + elf_section(hdr, hdr->e_shstrndx)->sh_offset; -} - -static inline unsigned int set_section_name(const char *name, - struct elfhdr *ehdr) -{ - char *strtab = elf_str_table(ehdr); - static int strtable_idx = 1; - int idx, ret = 0; - - idx = strtable_idx; - if ((strtab == NULL) || (name == NULL)) - return 0; - - ret = idx; - idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH); - strtable_idx = idx + 1; - - return ret; -} - -static int _do_minidump(void *handle, struct ramdump_segment *segments, - int nsegments) -{ - int ret, i; - struct ramdump_device *rd_dev = (struct ramdump_device *)handle; - struct elfhdr *ehdr; - struct elf_shdr *shdr; - unsigned long offset, strtbl_off; - - if (!rd_dev->consumer_present) { - pr_err("Ramdump(%s): No consumers. Aborting..\n", rd_dev->name); - return -EPIPE; - } - - rd_dev->segments = segments; - rd_dev->nsegments = nsegments; - - rd_dev->elfcore_size = sizeof(*ehdr) + - (sizeof(*shdr) * (nsegments + 2)) + MAX_STRTBL_SIZE; - ehdr = kzalloc(rd_dev->elfcore_size, GFP_KERNEL); - rd_dev->elfcore_buf = (char *)ehdr; - if (!rd_dev->elfcore_buf) - return -ENOMEM; - - memcpy(ehdr->e_ident, ELFMAG, SELFMAG); - ehdr->e_ident[EI_CLASS] = ELF_CLASS; - ehdr->e_ident[EI_DATA] = ELF_DATA; - ehdr->e_ident[EI_VERSION] = EV_CURRENT; - ehdr->e_ident[EI_OSABI] = ELF_OSABI; - ehdr->e_type = ET_CORE; - ehdr->e_machine = ELF_ARCH; - ehdr->e_version = EV_CURRENT; - ehdr->e_ehsize = sizeof(*ehdr); - ehdr->e_shoff = sizeof(*ehdr); - ehdr->e_shentsize = sizeof(*shdr); - ehdr->e_shstrndx = 1; - - - offset = rd_dev->elfcore_size; - shdr = (struct elf_shdr *)(ehdr + 1); - strtbl_off = sizeof(*ehdr) + sizeof(*shdr) * (nsegments + 2); - shdr++; - shdr->sh_type = SHT_STRTAB; - shdr->sh_offset = (elf_addr_t)strtbl_off; - shdr->sh_size = MAX_STRTBL_SIZE; - shdr->sh_entsize = 0; - shdr->sh_flags = 0; - shdr->sh_name = set_section_name("STR_TBL", ehdr); - shdr++; - - for (i = 0; i < nsegments; i++, shdr++) { - /* Update elf header */ - shdr->sh_type = SHT_PROGBITS; - shdr->sh_name = set_section_name(segments[i].name, ehdr); - shdr->sh_addr = (elf_addr_t)segments[i].address; - shdr->sh_size = segments[i].size; - shdr->sh_flags = SHF_WRITE; - shdr->sh_offset = offset; - shdr->sh_entsize = 0; - offset += shdr->sh_size; - } - ehdr->e_shnum = nsegments + 2; - - rd_dev->data_ready = 1; - rd_dev->ramdump_status = -1; - - reinit_completion(&rd_dev->ramdump_complete); - - /* Tell userspace that the data is ready */ - wake_up(&rd_dev->dump_wait_q); - - /* Wait (with a timeout) to let the ramdump complete */ - ret = wait_for_completion_timeout(&rd_dev->ramdump_complete, - msecs_to_jiffies(RAMDUMP_WAIT_MSECS)); - - if (!ret) { - pr_err("Ramdump(%s): Timed out waiting for userspace.\n", - rd_dev->name); - ret = -EPIPE; - } else { - ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE; - } - - rd_dev->data_ready = 0; - rd_dev->elfcore_size = 0; - kfree(rd_dev->elfcore_buf); - rd_dev->elfcore_buf = NULL; - return ret; -} - int do_ramdump(void *handle, struct ramdump_segment *segments, int nsegments) { return _do_ramdump(handle, segments, nsegments, false); } EXPORT_SYMBOL(do_ramdump); -int do_minidump(void *handle, struct ramdump_segment *segments, int nsegments) -{ - return _do_minidump(handle, segments, nsegments); -} -EXPORT_SYMBOL(do_minidump); - int do_elf_ramdump(void *handle, struct ramdump_segment *segments, int nsegments) { diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index 43e2e4d17648f0fd1cc1fda2f799a41a8ef59102..31de6e5c173cce91cf9f1f4d5f701826ff2a9b12 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -397,22 +397,18 @@ static int __scm_call_armv8_64(u64 x0, u64 x1, u64 x2, u64 x3, u64 x4, u64 x5, __asmeq("%1", R1_STR) __asmeq("%2", R2_STR) __asmeq("%3", R3_STR) - __asmeq("%4", R4_STR) - __asmeq("%5", R5_STR) - __asmeq("%6", R6_STR) - __asmeq("%7", R0_STR) - __asmeq("%8", R1_STR) - __asmeq("%9", R2_STR) - __asmeq("%10", R3_STR) - __asmeq("%11", R4_STR) - __asmeq("%12", R5_STR) - __asmeq("%13", R6_STR) + __asmeq("%4", R0_STR) + __asmeq("%5", R1_STR) + __asmeq("%6", R2_STR) + __asmeq("%7", R3_STR) + __asmeq("%8", R4_STR) + __asmeq("%9", R5_STR) + __asmeq("%10", R6_STR) #ifdef REQUIRES_SEC ".arch_extension sec\n" #endif "smc #0\n" - : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3), - "=r" (r4), "=r" (r5), "=r" (r6) + : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) : "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5), "r" (r6) : "x7", "x8", "x9", "x10", "x11", "x12", "x13", @@ -446,22 +442,18 @@ static int __scm_call_armv8_32(u32 w0, u32 w1, u32 w2, u32 w3, u32 w4, u32 w5, __asmeq("%1", R1_STR) __asmeq("%2", R2_STR) __asmeq("%3", R3_STR) - __asmeq("%4", R4_STR) - __asmeq("%5", R5_STR) - __asmeq("%6", R6_STR) - __asmeq("%7", R0_STR) - __asmeq("%8", R1_STR) - __asmeq("%9", R2_STR) - __asmeq("%10", R3_STR) - __asmeq("%11", R4_STR) - __asmeq("%12", R5_STR) - __asmeq("%13", R6_STR) + __asmeq("%4", R0_STR) + __asmeq("%5", R1_STR) + __asmeq("%6", R2_STR) + __asmeq("%7", R3_STR) + __asmeq("%8", R4_STR) + __asmeq("%9", R5_STR) + __asmeq("%10", R6_STR) #ifdef REQUIRES_SEC ".arch_extension sec\n" #endif "smc #0\n" - : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3), - "=r" (r4), "=r" (r5), "=r" (r6) + : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) : "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5), "r" (r6) : "x7", "x8", "x9", "x10", "x11", "x12", "x13", @@ -498,22 +490,18 @@ static int __scm_call_armv8_32(u32 w0, u32 w1, u32 w2, u32 w3, u32 w4, u32 w5, __asmeq("%1", R1_STR) __asmeq("%2", R2_STR) __asmeq("%3", R3_STR) - __asmeq("%4", R4_STR) - __asmeq("%5", R5_STR) - __asmeq("%6", R6_STR) - __asmeq("%7", R0_STR) - __asmeq("%8", R1_STR) - __asmeq("%9", R2_STR) - __asmeq("%10", R3_STR) - __asmeq("%11", R4_STR) - __asmeq("%12", R5_STR) - __asmeq("%13", R6_STR) + __asmeq("%4", R0_STR) + __asmeq("%5", R1_STR) + __asmeq("%6", R2_STR) + __asmeq("%7", R3_STR) + __asmeq("%8", R4_STR) + __asmeq("%9", R5_STR) + __asmeq("%10", R6_STR) #ifdef REQUIRES_SEC ".arch_extension sec\n" #endif "smc #0\n" - : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3), - "=r" (r4), "=r" (r5), "=r" (r6) + : "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) : "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5), "r" (r6)); @@ -1129,55 +1117,54 @@ int scm_is_call_available(u32 svc_id, u32 cmd_id) ret = scm_call(SCM_SVC_INFO, IS_CALL_AVAIL_CMD, &svc_cmd, sizeof(svc_cmd), &ret_val, sizeof(ret_val)); - if (!ret && ret_val) - return 1; - else - return 0; + if (ret) + return ret; + return ret_val; } desc.arginfo = SCM_ARGS(1); desc.args[0] = SCM_SIP_FNID(svc_id, cmd_id); - desc.ret[0] = 0; ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, IS_CALL_AVAIL_CMD), &desc); - if (!ret && desc.ret[0]) - return 1; - else - return 0; + if (ret) + return ret; + return desc.ret[0]; } EXPORT_SYMBOL(scm_is_call_available); #define GET_FEAT_VERSION_CMD 3 -int scm_get_feat_version(u32 feat, u64 *scm_ret) +int scm_get_feat_version(u32 feat) { struct scm_desc desc = {0}; int ret; if (!is_scm_armv8()) { if (scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD)) { - ret = scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD, - &feat, sizeof(feat), scm_ret, sizeof(*scm_ret)); - return ret; + u32 version; + if (!scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD, &feat, + sizeof(feat), &version, sizeof(version))) + return version; } + return 0; } ret = scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD); if (ret <= 0) - return -EAGAIN; + return 0; desc.args[0] = feat; desc.arginfo = SCM_ARGS(1); ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, GET_FEAT_VERSION_CMD), &desc); + if (!ret) + return desc.ret[0]; - *scm_ret = desc.ret[0]; - - return ret; + return 0; } EXPORT_SYMBOL(scm_get_feat_version); #define RESTORE_SEC_CFG 2 -int scm_restore_sec_cfg(u32 device_id, u32 spare, u64 *scm_ret) +int scm_restore_sec_cfg(u32 device_id, u32 spare, int *scm_ret) { struct scm_desc desc = {0}; int ret; diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c index e7a00cdb5b03f076b2c2194e544c9c4692f4f552..4307937d9f6d0d526eebb40bdfa269a1e4886fff 100644 --- a/drivers/soc/qcom/secure_buffer.c +++ b/drivers/soc/qcom/secure_buffer.c @@ -424,14 +424,13 @@ const char *msm_secure_vmid_to_string(int secure_vmid) bool msm_secure_v2_is_supported(void) { - u64 version; - int ret = scm_get_feat_version(FEATURE_ID_CP, &version); + int version = scm_get_feat_version(FEATURE_ID_CP); /* * if the version is < 1.1.0 then dynamic buffer allocation is * not supported */ - return (ret == 0) && (version >= MAKE_CP_VERSION(1, 1, 0)); + return version >= MAKE_CP_VERSION(1, 1, 0); } static int __init alloc_secure_shared_memory(void) diff --git a/drivers/soc/qcom/security_status.c b/drivers/soc/qcom/security_status.c new file mode 100644 index 0000000000000000000000000000000000000000..b158a52968bb65633267fbf00a3c3de01b36a313 --- /dev/null +++ b/drivers/soc/qcom/security_status.c @@ -0,0 +1,55 @@ +/* + * Author: Nandhakumar Rangasamy + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define SECURITY_ENABLED 0x2 + +static int security_status = -1; + +static int __init security_config_setup(char *p) +{ + unsigned long res; + + if (!p || !*p) + return -EINVAL; + + if (!kstrtoul(p, 0, &res)) { + if (res & SECURITY_ENABLED) + security_status = SECURITY_ON; + else + security_status = SECURITY_OFF; + } + + pr_info("system booted with SECURITY_STATUS : %s\n", + security_status ? "ON" : "OFF"); + return 0; +} +early_param("oemandroidboot.securityflags", security_config_setup); + +int get_security_status(int *status) +{ + if (security_status == -1) + return -EINVAL; + else { + *status = security_status; + return 0; + } +} diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index f19db5fe99b3eb530065d63f3bb8907e2b90c721..985b7382700e014c38afd26c6be644e4ab50d4a7 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -11,6 +11,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "servloc: %s: " fmt, __func__ diff --git a/drivers/soc/qcom/smp2p_spinlock_test.c b/drivers/soc/qcom/smp2p_spinlock_test.c index 1fe4411eebde66d7594f82f9c6071f46cc1a819b..74aac52b528560a2d2307203513746b0978b78d9 100644 --- a/drivers/soc/qcom/smp2p_spinlock_test.c +++ b/drivers/soc/qcom/smp2p_spinlock_test.c @@ -1,6 +1,6 @@ /* drivers/soc/qcom/smp2p_spinlock_test.c * - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, 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 @@ -522,7 +522,7 @@ static void smp2p_ut_remote_spinlock_ssr(struct seq_file *s) int spinlock_owner = 0; struct workqueue_struct *ws = NULL; - struct rmt_spinlock_work_item work_item = { .has_locked = false }; + struct rmt_spinlock_work_item work_item; seq_printf(s, " Running %s Test\n", __func__); diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 74dbd4d42272f3af8a1d0ee730a378d9b7ebd73b..c959342c08ce9ee2cc99b8216f89f2523c01176d 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -11,6 +11,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * SOC Info Routines * @@ -29,6 +34,9 @@ #include #include +#ifdef CONFIG_RAMDUMP_TAGS +#include +#endif #include #include @@ -47,6 +55,18 @@ #define SMEM_IMAGE_VERSION_PARTITION_APPS 10 static DECLARE_RWSEM(current_image_rwsem); + +#ifdef CONFIG_RAMDUMP_TAGS +#define RDT_ADD_UINT(func, name) \ + do { \ + res = func(); \ + if (res != 0) { \ + snprintf(buf, sizeof(buf), "%u (0x%.8X)", res, res); \ + rdtags_add_tag(name, buf, strnlen(buf, sizeof(buf))); \ + } \ + } while (0) +#endif + enum { HW_PLATFORM_UNKNOWN = 0, HW_PLATFORM_SURF = 1, @@ -566,10 +586,6 @@ static struct msm_soc_info cpu_of_id[] = { [318] = {MSM_CPU_630, "SDM630"}, [327] = {MSM_CPU_630, "SDA630"}, - /* 636 ID */ - [345] = {MSM_CPU_636, "SDM636"}, - [346] = {MSM_CPU_636, "SDA636"}, - /* Uninitialized IDs are not known to run Linux. MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are considered as unknown CPU. */ @@ -1293,14 +1309,6 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 327; strlcpy(dummy_socinfo.build_id, "sda630 - ", sizeof(dummy_socinfo.build_id)); - } else if (early_machine_is_sdm636()) { - dummy_socinfo.id = 345; - strlcpy(dummy_socinfo.build_id, "sdm636 - ", - sizeof(dummy_socinfo.build_id)); - } else if (early_machine_is_sda636()) { - dummy_socinfo.id = 346; - strlcpy(dummy_socinfo.build_id, "sda636 - ", - sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_apq8098()) { dummy_socinfo.id = 319; strlcpy(dummy_socinfo.build_id, "apq8098 - ", @@ -1571,6 +1579,34 @@ static void socinfo_select_format(void) } } +#ifdef CONFIG_RAMDUMP_TAGS +/* Extracts information from QC:s socinfo to get + * information about the hardware revisions of main soc + */ +static void add_socinfo_tags(void) +{ + uint32_t res; + char buf[64]; + char *str; + + RDT_ADD_UINT(read_cpuid_id, "cpuid_id"); + RDT_ADD_UINT(socinfo_get_platform_version, "socinfo_platform_version"); + RDT_ADD_UINT(socinfo_get_platform_subtype, "socinfo_platform_subtype"); + RDT_ADD_UINT(socinfo_get_platform_type, "socinfo_platform_type"); + RDT_ADD_UINT(socinfo_get_raw_id, "socinfo_raw_id"); + RDT_ADD_UINT(socinfo_get_id, "socinfo_id"); + + res = socinfo_get_version(); + snprintf(buf, sizeof(buf), "%u.%u", SOCINFO_VERSION_MAJOR(res), + SOCINFO_VERSION_MINOR(res)); + rdtags_add_tag("socinfo_version", buf, strnlen(buf, sizeof(buf))); + + str = socinfo_get_build_id(); + if (str) + rdtags_add_tag("socinfo_build_id", str, strlen(str)); +} +#endif + int __init socinfo_init(void) { static bool socinfo_init_done; @@ -1599,6 +1635,9 @@ int __init socinfo_init(void) socinfo_print(); arch_read_hardware_id = msm_read_hardware_id; socinfo_init_done = true; +#ifdef CONFIG_RAMDUMP_TAGS + add_socinfo_tags(); +#endif return 0; } diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 4e89f9aed58b84b00214f586875724077e5e740e..e4afce02afc76b33fe714e00f56c2786cbb1d1ac 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -196,7 +196,6 @@ struct spcom_channel { * glink state: CONNECTED / LOCAL_DISCONNECTED, REMOTE_DISCONNECTED */ unsigned glink_state; - bool is_closing; /* Events notification */ struct completion connect; @@ -484,17 +483,7 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) switch (event) { case GLINK_CONNECTED: pr_debug("GLINK_CONNECTED, ch name [%s].\n", ch->name); - mutex_lock(&ch->lock); - - if (ch->is_closing) { - pr_err("Unexpected CONNECTED while closing [%s].\n", - ch->name); - mutex_unlock(&ch->lock); - return; - } - ch->glink_state = event; - /* * if spcom_notify_state() is called within glink_open() * then ch->glink_handle is not updated yet. @@ -504,16 +493,7 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) ch->glink_handle = handle; } - /* signal before unlock mutex & before calling glink */ - complete_all(&ch->connect); - - /* - * Prepare default rx buffer. - * glink_queue_rx_intent() can be called only AFTER connected. - * We do it here, ASAP, to allow rx data. - */ - - pr_debug("call glink_queue_rx_intent() ch [%s].\n", ch->name); + /* prepare default rx buffer after connected */ ret = glink_queue_rx_intent(ch->glink_handle, ch, ch->rx_buf_size); if (ret) { @@ -523,9 +503,7 @@ static void spcom_notify_state(void *handle, const void *priv, unsigned event) ch->rx_buf_size); ch->rx_buf_ready = true; } - - pr_debug("GLINK_CONNECTED, ch name [%s] done.\n", ch->name); - mutex_unlock(&ch->lock); + complete_all(&ch->connect); break; case GLINK_LOCAL_DISCONNECTED: /* @@ -690,13 +668,6 @@ static int spcom_init_channel(struct spcom_channel *ch, const char *name) ch->glink_state = GLINK_LOCAL_DISCONNECTED; ch->actual_rx_size = 0; ch->rx_buf_size = SPCOM_RX_BUF_SIZE; - ch->is_closing = false; - ch->glink_handle = NULL; - ch->ref_count = 0; - ch->rx_abort = false; - ch->tx_abort = false; - ch->txn_id = INITIAL_TXN_ID; /* use non-zero nonce for debug */ - ch->pid = 0; return 0; } @@ -767,8 +738,6 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec) /* init completion before calling glink_open() */ reinit_completion(&ch->connect); - ch->is_closing = false; - handle = glink_open(&cfg); if (IS_ERR_OR_NULL(handle)) { pr_err("glink_open failed.\n"); @@ -783,8 +752,6 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec) ch->pid = current_pid(); ch->txn_id = INITIAL_TXN_ID; - mutex_unlock(&ch->lock); - pr_debug("Wait for connection on channel [%s] timeout_msec [%d].\n", name, timeout_msec); @@ -801,6 +768,8 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec) pr_debug("Channel [%s] opened, no timeout.\n", name); } + mutex_unlock(&ch->lock); + return 0; exit_err: mutex_unlock(&ch->lock); @@ -827,8 +796,6 @@ static int spcom_close(struct spcom_channel *ch) return 0; } - ch->is_closing = true; - ret = glink_close(ch->glink_handle); if (ret) pr_err("glink_close() fail, ret [%d].\n", ret); @@ -844,7 +811,6 @@ static int spcom_close(struct spcom_channel *ch) ch->pid = 0; pr_debug("Channel closed [%s].\n", ch->name); - mutex_unlock(&ch->lock); return 0; @@ -1139,7 +1105,6 @@ struct spcom_client *spcom_register_client(struct spcom_client_info *info) ch = spcom_find_channel_by_name(name); if (!ch) { pr_err("channel %s doesn't exist, load App first.\n", name); - kfree(client); return NULL; } @@ -1327,7 +1292,6 @@ struct spcom_server *spcom_register_service(struct spcom_service_info *info) ch = spcom_find_channel_by_name(name); if (!ch) { pr_err("channel %s doesn't exist, load App first.\n", name); - kfree(server); return NULL; } @@ -2788,7 +2752,7 @@ static int __init spcom_init(void) { int ret; - pr_info("spcom driver version 1.1 17-July-2017.\n"); + pr_info("spcom driver Ver 1.0 23-Nov-2015.\n"); ret = platform_driver_register(&spcom_driver); if (ret) diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index 8bf5f8eb64adf5561b6310f6731098527b97e027..9395b04d23e71bfbb57801184d34793d702f2dae 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -804,6 +809,7 @@ static void log_failure_reason(const struct pil_tz_data *d) strlcpy(reason, smem_reason, min(size, MAX_SSR_REASON_LEN)); pr_err("%s subsystem failure reason: %s.\n", name, reason); + update_crash_reason(d->subsys, reason, size); smem_reason[0] = '\0'; wmb(); @@ -850,7 +856,7 @@ static int subsys_ramdump(int enable, const struct subsys_desc *subsys) if (!enable) return 0; - return pil_do_ramdump(&d->desc, d->ramdump_dev, NULL); + return pil_do_ramdump(&d->desc, d->ramdump_dev); } static void subsys_free_memory(const struct subsys_desc *subsys) diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index ae249f3823393ac5db905df6dbe1f78fadb2cfb5..05c5c6b764e6acdfba09eeac3afd0825963d5969 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "subsys-restart: %s(): " fmt, __func__ @@ -28,7 +33,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -171,6 +179,12 @@ struct subsys_device { int restart_level; int crash_count; struct subsys_soc_restart_order *restart_order; +#ifdef CONFIG_DEBUG_FS + struct dentry *reason_dentry; + char crash_reason[SUBSYS_CRASH_REASON_LEN]; + int data_ready; + wait_queue_head_t subsys_debug_q; +#endif bool do_ramdump_on_put; struct cdev char_dev; dev_t dev_no; @@ -180,6 +194,8 @@ struct subsys_device { struct list_head list; }; +static void subsys_notify_crash_reason(struct subsys_device *subsys); + static struct subsys_device *to_subsys(struct device *d) { return container_of(d, struct subsys_device, dev); @@ -1004,7 +1020,7 @@ static void subsystem_restart_wq_func(struct work_struct *work) spin_lock_irqsave(&track->s_lock, flags); track->p_state = SUBSYS_RESTARTING; spin_unlock_irqrestore(&track->s_lock, flags); - + subsys_notify_crash_reason(dev); /* Collect ram dumps for all subsystems in order here */ for_each_subsys_device(list, count, NULL, subsystem_ramdump); @@ -1147,6 +1163,19 @@ int subsystem_restart(const char *name) } EXPORT_SYMBOL(subsystem_restart); +int subsystem_crash_reason(const char *name, char *msg) +{ + struct subsys_device *dev = find_subsys(name); + + if (!dev) + return -ENODEV; + update_crash_reason(dev, msg, SUBSYS_CRASH_REASON_LEN); + subsys_notify_crash_reason(dev); + + return 0; +} +EXPORT_SYMBOL(subsystem_crash_reason); + int subsystem_crashed(const char *name) { struct subsys_device *dev = find_subsys(name); @@ -1219,6 +1248,101 @@ void notify_proxy_unvote(struct device *device) notify_each_subsys_device(&dev, 1, SUBSYS_PROXY_UNVOTE, NULL); } +#ifdef CONFIG_DEBUG_FS +void update_crash_reason(struct subsys_device *subsys, + char *smem_reason, int size) +{ + memcpy(subsys->crash_reason, smem_reason, size); + subsys->data_ready = 1; +} + +static void subsys_notify_crash_reason(struct subsys_device *subsys) +{ + if (subsys->data_ready && subsys->restart_level != RESET_SOC) + wake_up(&subsys->subsys_debug_q); +} + +static ssize_t subsys_debugfs_reason_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + int r; + char buf[SUBSYS_CRASH_REASON_LEN]; + ssize_t size; + struct subsys_device *subsys = filp->private_data; + + r = snprintf(buf, sizeof(buf), "%s", subsys->crash_reason); + size = simple_read_from_buffer(ubuf, cnt, ppos, buf, r); + if (*ppos == r) { + memset(subsys->crash_reason, 0, sizeof(subsys->crash_reason)); + subsys->data_ready = 0; + } + + return size; +} + +static unsigned int subsys_debugfs_reason_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct subsys_device *subsys = filp->private_data; + unsigned int mask = 0; + + if (subsys->data_ready) + mask |= (POLLIN | POLLRDNORM); + + poll_wait(filp, &subsys->subsys_debug_q, wait); + return mask; +} + +static const struct file_operations subsys_debugfs_reason_fops = { + .open = simple_open, + .read = subsys_debugfs_reason_read, + .poll = subsys_debugfs_reason_poll, + .llseek = default_llseek, +}; + +static struct dentry *subsys_base_dir; +static struct dentry *subsys_reason_dir; + +static int __init subsys_debugfs_init(void) +{ + subsys_base_dir = debugfs_create_dir("msm_subsys", NULL); + if (subsys_base_dir) + subsys_reason_dir = debugfs_create_dir("crash_reason", + subsys_base_dir); + return !subsys_base_dir ? -ENOMEM : 0; +} + +static void subsys_debugfs_exit(void) +{ + if (subsys_reason_dir) + debugfs_remove_recursive(subsys_reason_dir); + debugfs_remove_recursive(subsys_base_dir); +} + +static int subsys_debugfs_add(struct subsys_device *subsys) +{ + if (!subsys_base_dir) + return -ENOMEM; + + if (subsys_reason_dir) + subsys->reason_dentry = debugfs_create_file(subsys->desc->name, + S_IRUGO | S_IWUSR, subsys_reason_dir, + subsys, &subsys_debugfs_reason_fops); + return !subsys->reason_dentry ? -ENOMEM : 0; +} + +static void subsys_debugfs_remove(struct subsys_device *subsys) +{ + debugfs_remove(subsys->reason_dentry); +} +#else +static int __init subsys_debugfs_init(void) { return 0; }; +static void subsys_debugfs_exit(void) { } +static int subsys_debugfs_add(struct subsys_device *subsys) { return 0; } +static void subsys_debugfs_remove(struct subsys_device *subsys) { } +static void subsys_notify_crash_reason(struct subsys_device *subsys) { } +#endif + static int subsys_device_open(struct inode *inode, struct file *file) { struct subsys_device *device, *subsys_dev = 0; @@ -1658,8 +1782,19 @@ struct subsys_device *subsys_register(struct subsys_desc *desc) mutex_init(&subsys->track.lock); + ret = subsys_debugfs_add(subsys); + if (ret) { + ida_simple_remove(&subsys_ida, subsys->id); + wakeup_source_trash(&subsys->ssr_wlock); + kfree(subsys); + return ERR_PTR(ret); + } + + init_waitqueue_head(&subsys->subsys_debug_q); + ret = device_register(&subsys->dev); if (ret) { + subsys_debugfs_remove(subsys); put_device(&subsys->dev); return ERR_PTR(ret); } @@ -1721,6 +1856,7 @@ err_setup_irqs: if (ofnode) subsys_remove_restart_order(ofnode); err_register: + subsys_debugfs_remove(subsys); device_unregister(&subsys->dev); return ERR_PTR(ret); } @@ -1749,6 +1885,7 @@ void subsys_unregister(struct subsys_device *subsys) WARN_ON(subsys->count); device_unregister(&subsys->dev); mutex_unlock(&subsys->track.lock); + subsys_debugfs_remove(subsys); subsys_char_device_remove(subsys); sysmon_notifier_unregister(subsys->desc); if (subsys->desc->edge) @@ -1788,6 +1925,9 @@ static int __init subsys_restart_init(void) ret = bus_register(&subsys_bus_type); if (ret) goto err_bus; + ret = subsys_debugfs_init(); + if (ret) + goto err_debugfs; char_class = class_create(THIS_MODULE, "subsys"); if (IS_ERR(char_class)) { @@ -1806,6 +1946,8 @@ static int __init subsys_restart_init(void) err_soc: class_destroy(char_class); err_class: + subsys_debugfs_exit(); +err_debugfs: bus_unregister(&subsys_bus_type); err_bus: destroy_workqueue(ssr_wq); diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c index 625030f1f2560d4c70baa763adefd2f7bc65cd2b..aaafb1c1c1ee9120d1b5f1a0a887054f37df444b 100644 --- a/drivers/soc/qcom/watchdog_v2.c +++ b/drivers/soc/qcom/watchdog_v2.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -134,8 +139,6 @@ static int msm_watchdog_suspend(struct device *dev) return 0; __raw_writel(1, wdog_dd->base + WDT0_RST); if (wdog_dd->wakeup_irq_enable) { - /* Make sure register write is complete before proceeding */ - mb(); wdog_dd->last_pet = sched_clock(); return 0; } @@ -150,15 +153,8 @@ static int msm_watchdog_resume(struct device *dev) { struct msm_watchdog_data *wdog_dd = (struct msm_watchdog_data *)dev_get_drvdata(dev); - if (!enable) - return 0; - if (wdog_dd->wakeup_irq_enable) { - __raw_writel(1, wdog_dd->base + WDT0_RST); - /* Make sure register write is complete before proceeding */ - mb(); - wdog_dd->last_pet = sched_clock(); + if (!enable || wdog_dd->wakeup_irq_enable) return 0; - } __raw_writel(1, wdog_dd->base + WDT0_EN); __raw_writel(1, wdog_dd->base + WDT0_RST); mb(); @@ -500,6 +496,10 @@ static irqreturn_t wdog_bark_handler(int irq, void *dev_id) wdog_dd->last_pet, nanosec_rem / 1000); if (wdog_dd->do_ipi_ping) dump_cpu_alive_mask(wdog_dd); +#ifdef CONFIG_MSM_FORCE_PANIC_ON_WDOG_BARK + /*Causing a panic instead of a watchdog bite */ + panic("Watchdog bark triggered!"); +#endif msm_trigger_wdog_bite(); panic("Failed to cause a watchdog bite! - Falling back to kernel panic!"); return IRQ_HANDLED; diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index 85c2b92f547483140462e30f6fcb52da0fa77505..5fe3c572628b425c0b38540ae1316f5f824a0b79 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -570,7 +570,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, mutex_lock(&wpriv->glink_mutex); if (wpriv->ch) { - dev_err_ratelimited(wpriv->dev, "%s: glink ch memory is already allocated\n", + dev_err(wpriv->dev, "%s: glink ch memory is already allocated\n", __func__); ret = -EINVAL; goto done; @@ -579,7 +579,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, no_of_channels = pkt->no_of_channels; if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) { - dev_err_ratelimited(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n", + dev_err(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n", __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS); ret = -EINVAL; goto done; @@ -598,20 +598,20 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, size += WDSP_CH_CFG_SIZE; if (size > pkt_size) { - dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", + dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", __func__, size, pkt_size); ret = -EINVAL; goto err_ch_mem; } if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) { - dev_err_ratelimited(wpriv->dev, "%s: Invalid no_of_intents = %d\n", + dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n", __func__, ch_cfg->no_of_intents); ret = -EINVAL; goto err_ch_mem; } size += (sizeof(u32) * ch_cfg->no_of_intents); if (size > pkt_size) { - dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", + dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n", __func__, size, pkt_size); ret = -EINVAL; goto err_ch_mem; @@ -746,7 +746,7 @@ static ssize_t wdsp_glink_read(struct file *file, char __user *buf, } if (count > WDSP_MAX_READ_SIZE) { - dev_info_ratelimited(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n", + dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n", __func__, count); count = WDSP_MAX_READ_SIZE; } @@ -778,7 +778,7 @@ static ssize_t wdsp_glink_read(struct file *file, char __user *buf, if (ret1) { mutex_unlock(&wpriv->rsp_mutex); - dev_err_ratelimited(wpriv->dev, "%s: copy_to_user failed %d\n", + dev_err(wpriv->dev, "%s: copy_to_user failed %d\n", __func__, ret); ret = -EFAULT; goto done; @@ -824,7 +824,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, if ((count < WDSP_WRITE_PKT_SIZE) || (count > WDSP_MAX_WRITE_SIZE)) { - dev_err_ratelimited(wpriv->dev, "%s: Invalid count = %zd\n", + dev_err(wpriv->dev, "%s: Invalid count = %zd\n", __func__, count); ret = -EINVAL; goto done; @@ -841,7 +841,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, ret = copy_from_user(tx_buf->buf, buf, count); if (ret) { - dev_err_ratelimited(wpriv->dev, "%s: copy_from_user failed %d\n", + dev_err(wpriv->dev, "%s: copy_from_user failed %d\n", __func__, ret); ret = -EFAULT; goto free_buf; @@ -852,7 +852,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, case WDSP_REG_PKT: if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE + WDSP_CH_CFG_SIZE)) { - dev_err_ratelimited(wpriv->dev, "%s: Invalid reg pkt size = %zd\n", + dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n", __func__, count); ret = -EINVAL; goto free_buf; @@ -861,7 +861,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, (struct wdsp_reg_pkt *)wpkt->payload, count); if (IS_ERR_VALUE(ret)) - dev_err_ratelimited(wpriv->dev, "%s: glink register failed, ret = %d\n", + dev_err(wpriv->dev, "%s: glink register failed, ret = %d\n", __func__, ret); vfree(tx_buf); break; @@ -871,7 +871,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, GLINK_LINK_STATE_UP), msecs_to_jiffies(TIMEOUT_MS)); if (!ret) { - dev_err_ratelimited(wpriv->dev, "%s: Link state wait timeout\n", + dev_err(wpriv->dev, "%s: Link state wait timeout\n", __func__); ret = -ETIMEDOUT; goto free_buf; @@ -881,7 +881,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, break; case WDSP_CMD_PKT: if (count <= (WDSP_WRITE_PKT_SIZE + WDSP_CMD_PKT_SIZE)) { - dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n", + dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n", __func__, count); ret = -EINVAL; goto free_buf; @@ -889,7 +889,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, mutex_lock(&wpriv->glink_mutex); if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) { mutex_unlock(&wpriv->glink_mutex); - dev_err_ratelimited(wpriv->dev, "%s: Link state is Down\n", + dev_err(wpriv->dev, "%s: Link state is Down\n", __func__); ret = -ENETRESET; @@ -901,7 +901,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, sizeof(struct wdsp_cmd_pkt) + cpkt->payload_size; if (count < pkt_max_size) { - dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n", + dev_err(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n", __func__, count, pkt_max_size); ret = -EINVAL; goto free_buf; @@ -917,7 +917,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, } } if (!tx_buf->ch) { - dev_err_ratelimited(wpriv->dev, "%s: Failed to get glink channel\n", + dev_err(wpriv->dev, "%s: Failed to get glink channel\n", __func__); ret = -EINVAL; goto free_buf; @@ -928,7 +928,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, GLINK_CONNECTED), msecs_to_jiffies(TIMEOUT_MS)); if (!ret) { - dev_err_ratelimited(wpriv->dev, "%s: glink channel %s is not in connected state %d\n", + dev_err(wpriv->dev, "%s: glink channel %s is not in connected state %d\n", __func__, tx_buf->ch->ch_cfg.name, tx_buf->ch->channel_state); ret = -ETIMEDOUT; @@ -940,8 +940,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf, queue_work(wpriv->work_queue, &tx_buf->tx_work); break; default: - dev_err_ratelimited(wpriv->dev, "%s: Invalid packet type\n", - __func__); + dev_err(wpriv->dev, "%s: Invalid packet type\n", __func__); ret = -EINVAL; vfree(tx_buf); break; @@ -987,7 +986,6 @@ static int wdsp_glink_open(struct inode *inode, struct file *file) goto err_wq; } - wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN; init_completion(&wpriv->rsp_complete); init_waitqueue_head(&wpriv->link_state_wait); mutex_init(&wpriv->rsp_mutex); diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c index 1dcaba2e79f65987d89aab60512bc6877a3c30f4..4eb069b6d036e2236dc39a6761e999fbb89c0621 100644 --- a/drivers/soundwire/swr-wcd-ctrl.c +++ b/drivers/soundwire/swr-wcd-ctrl.c @@ -397,17 +397,11 @@ static int swrm_clk_request(struct swr_mstr_ctrl *swrm, bool enable) return -EINVAL; if (enable) { - swrm->clk_ref_count++; - if (swrm->clk_ref_count == 1) { - swrm->clk(swrm->handle, true); - swrm->state = SWR_MSTR_UP; - } - } else if (--swrm->clk_ref_count == 0) { + swrm->clk(swrm->handle, true); + swrm->state = SWR_MSTR_UP; + } else { swrm->clk(swrm->handle, false); swrm->state = SWR_MSTR_DOWN; - } else if (swrm->clk_ref_count < 0) { - pr_err("%s: swrm clk count mismatch\n", __func__); - swrm->clk_ref_count = 0; } return 0; } @@ -1175,10 +1169,7 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev) u8 devnum = 0; int ret = IRQ_HANDLED; - mutex_lock(&swrm->reslock); - swrm_clk_request(swrm, true); - mutex_unlock(&swrm->reslock); - + pm_runtime_get_sync(&swrm->pdev->dev); intr_sts = swrm->read(swrm->handle, SWRM_INTERRUPT_STATUS); intr_sts &= SWRM_INTERRUPT_STATUS_RMSK; for (i = 0; i < SWRM_INTERRUPT_MAX; i++) { @@ -1266,10 +1257,8 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev) break; } } - - mutex_lock(&swrm->reslock); - swrm_clk_request(swrm, false); - mutex_unlock(&swrm->reslock); + pm_runtime_mark_last_busy(&swrm->pdev->dev); + pm_runtime_put_autosuspend(&swrm->pdev->dev); return ret; } @@ -1459,7 +1448,6 @@ static int swrm_probe(struct platform_device *pdev) swrm->wcmd_id = 0; swrm->slave_status = 0; swrm->num_rx_chs = 0; - swrm->clk_ref_count = 0; swrm->state = SWR_MSTR_RESUME; init_completion(&swrm->reset); init_completion(&swrm->broadcast); @@ -1725,8 +1713,10 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) mutex_lock(&swrm->reslock); if ((swrm->state == SWR_MSTR_RESUME) || (swrm->state == SWR_MSTR_UP)) { - dev_dbg(swrm->dev, "%s: SWR master is already UP: %d\n", - __func__, swrm->state); + dev_dbg(swrm->dev, "%s: SWR master is already UP: %d. Do slave reset\n", + __func__, swrm->state); + list_for_each_entry(swr_dev, &mstr->devices, dev_list) + ret = swr_reset_device(swr_dev); } else { pm_runtime_mark_last_busy(&pdev->dev); mutex_unlock(&swrm->reslock); diff --git a/drivers/soundwire/swr-wcd-ctrl.h b/drivers/soundwire/swr-wcd-ctrl.h index 104ac8f6f510c91f9c2f110669e19eb446f4b47e..b7a3edac3e00fb5140d840aa4d266ec70efff24a 100755 --- a/drivers/soundwire/swr-wcd-ctrl.h +++ b/drivers/soundwire/swr-wcd-ctrl.h @@ -78,7 +78,6 @@ struct swr_mstr_ctrl { struct device *dev; struct resource *supplies; struct clk *mclk; - int clk_ref_count; struct completion reset; struct completion broadcast; struct mutex mlock; diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 1ddba9ae8c0fb8dee83032766611821cd00f285e..7d3af3eacf57d7c7e82722fadf2f1fdece1a8ed2 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -651,7 +651,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) buf = t->rx_buf; t->rx_dma = dma_map_single(&spi->dev, buf, t->len, DMA_FROM_DEVICE); - if (dma_mapping_error(&spi->dev, !t->rx_dma)) { + if (!t->rx_dma) { ret = -EFAULT; goto err_rx_map; } @@ -665,7 +665,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) buf = (void *)t->tx_buf; t->tx_dma = dma_map_single(&spi->dev, buf, t->len, DMA_TO_DEVICE); - if (dma_mapping_error(&spi->dev, t->tx_dma)) { + if (!t->tx_dma) { ret = -EFAULT; goto err_tx_map; } diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 9f161b2631f2b52d2f694e099fd267431cb2f2c1..c83910dd2ec68846a76a227983867d6519fda2c4 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -15,6 +15,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -696,6 +701,9 @@ static const struct of_device_id spidev_dt_ids[] = { { .compatible = "rohm,dh2228fv" }, { .compatible = "lineartechnology,ltc2488" }, { .compatible = "qcom,spi-msm-codec-slave", }, +#ifdef CONFIG_ONESEG_TUNER_SMTVJ19X + { .compatible = "sony,vj190-spi", }, +#endif {}, }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index d3130cfd6433251c9bb971439dbeb3963ba11652..1af43aeeca6adce222776bd147eb140ada310dcc 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 26629b856f91cf97ac19ccd9e4fba027623d7d20..537a969ce6b613301726374619d8561a6ba94880 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -47,6 +47,16 @@ config ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES /sys/module/lowmemorykiller/parameters/adj and convert them to oom_score_adj values. +config ANDROID_LOW_MEMORY_KILLER_STATS + bool "Android Low Memory Killer: collect statistics" + default n + help + Create a file in /proc/lmkstats that includes + collected statistics about kills, scans and counts + and interaction with the shrinker. Its content + will be different depending on lmk implementation used + in TNG lowmemorykiller. + config SYNC bool "Synchronization framework" default n diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index b0b47ae4c0ead769204fc390806d415700033ed5..4d93ad3aff56b2a71c78fec99e644133505e639a 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o +obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER_STATS) += lowmemorykiller_stats.o obj-$(CONFIG_SYNC) += sync.o sync_debug.o obj-$(CONFIG_SW_SYNC) += sw_sync.o obj-$(CONFIG_ONESHOT_SYNC) += oneshot_sync.o diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 28c9afe538ca688bbdbc5c4db2320a5b8de3af7e..5aa46fff5cf3d1e83b1f9ae0c52ec05d652a5589 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -15,6 +15,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "ashmem: " fmt diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 067cd58375a442289b80df9c1f048b8c412a525b..07fc21797f0f8f2178fea4a13940cd00683600ab 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -264,7 +264,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, mutex_lock(&dev->buffer_lock); ion_buffer_add(dev, buffer); mutex_unlock(&dev->buffer_lock); - atomic_long_add(len, &heap->total_allocated); + atomic_add(len, &heap->total_allocated); return buffer; err: @@ -282,7 +282,7 @@ void ion_buffer_destroy(struct ion_buffer *buffer) buffer->heap->ops->unmap_kernel(buffer->heap, buffer); buffer->heap->ops->unmap_dma(buffer->heap, buffer); - atomic_long_sub(buffer->size, &buffer->heap->total_allocated); + atomic_sub(buffer->size, &buffer->heap->total_allocated); buffer->heap->ops->free(buffer); vfree(buffer->pages); kfree(buffer); @@ -320,7 +320,7 @@ static void ion_buffer_add_to_handle(struct ion_buffer *buffer) { mutex_lock(&buffer->lock); if (buffer->handle_count == 0) - atomic_long_add(buffer->size, &buffer->heap->total_handles); + atomic_add(buffer->size, &buffer->heap->total_handles); buffer->handle_count++; mutex_unlock(&buffer->lock); @@ -346,7 +346,7 @@ static void ion_buffer_remove_from_handle(struct ion_buffer *buffer) task = current->group_leader; get_task_comm(buffer->task_comm, task); buffer->pid = task_pid_nr(task); - atomic_long_sub(buffer->size, &buffer->heap->total_handles); + atomic_sub(buffer->size, &buffer->heap->total_handles); } mutex_unlock(&buffer->lock); } @@ -1951,10 +1951,10 @@ void show_ion_usage(struct ion_device *dev) "Total orphaned size"); pr_info("---------------------------------\n"); plist_for_each_entry(heap, &dev->heaps, node) { - pr_info("%16.s 0x%16.lx 0x%16.lx\n", - heap->name, atomic_long_read(&heap->total_allocated), - atomic_long_read(&heap->total_allocated) - - atomic_long_read(&heap->total_handles)); + pr_info("%16.s 0x%16.x 0x%16.x\n", + heap->name, atomic_read(&heap->total_allocated), + atomic_read(&heap->total_allocated) - + atomic_read(&heap->total_handles)); if (heap->debug_show) heap->debug_show(heap, NULL, 0); diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index d932db4f9810dd0d1f6983ba483b44f1ff6130b5..dfb6d2f77af18ed16a22233fbedffc05c1dd306f 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -237,12 +237,10 @@ void ion_cma_heap_destroy(struct ion_heap *heap) static void ion_secure_cma_free(struct ion_buffer *buffer) { - int i, ret = 0; + int ret = 0; int source_vm; int dest_vmid; int dest_perms; - struct sg_table *sgt; - struct scatterlist *sg; struct ion_cma_buffer_info *info = buffer->priv_virt; source_vm = get_secure_vmid(buffer->flags); @@ -253,17 +251,14 @@ static void ion_secure_cma_free(struct ion_buffer *buffer) dest_vmid = VMID_HLOS; dest_perms = PERM_READ | PERM_WRITE | PERM_EXEC; - sgt = info->table; - ret = hyp_assign_table(sgt, &source_vm, 1, &dest_vmid, &dest_perms, 1); + ret = hyp_assign_table(info->table, &source_vm, 1, + &dest_vmid, &dest_perms, 1); if (ret) { pr_err("%s: Not freeing memory since assign failed\n", __func__); return; } - for_each_sg(sgt->sgl, sg, sgt->nents, i) - ClearPagePrivate(sg_page(sg)); - ion_cma_free(buffer); } @@ -271,13 +266,11 @@ static int ion_secure_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long len, unsigned long align, unsigned long flags) { - int i, ret = 0; + int ret = 0; int source_vm; int dest_vm; int dest_perms; struct ion_cma_buffer_info *info; - struct sg_table *sgt; - struct scatterlist *sg; source_vm = VMID_HLOS; dest_vm = get_secure_vmid(flags); @@ -299,17 +292,12 @@ static int ion_secure_cma_allocate(struct ion_heap *heap, } info = buffer->priv_virt; - sgt = info->table; - ret = hyp_assign_table(sgt, &source_vm, 1, &dest_vm, &dest_perms, 1); + ret = hyp_assign_table(info->table, &source_vm, 1, + &dest_vm, &dest_perms, 1); if (ret) { pr_err("%s: Assign call failed\n", __func__); goto err; } - - /* Set the private bit to indicate that we've secured this */ - for_each_sg(sgt->sgl, sg, sgt->nents, i) - SetPagePrivate(sg_page(sg)); - return ret; err: diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 513d015a5ace112217e2772a91e28ca4ef3179df..65c30c497fb27bd582cae1d7deb02d8907020995 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -13,18 +13,29 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include #include #include +#include +#include #include +#include #include #include #include +#include #include "ion_priv.h" +#define ION_PAGE_CACHE 1 + static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) { struct page *page; @@ -51,12 +62,18 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool, struct page *page) { ion_page_pool_free_set_cache_policy(pool, page); + if (pool->inode && pool->order == 0) { + lock_page(page); + __ClearPageMovable(page); + unlock_page(page); + } __free_pages(page, pool->order); } static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) { - mutex_lock(&pool->mutex); + spin_lock(&pool->lock); + page->private = ION_PAGE_CACHE; if (PageHighMem(page)) { list_add_tail(&page->lru, &pool->high_items); pool->high_count++; @@ -64,7 +81,10 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) list_add_tail(&page->lru, &pool->low_items); pool->low_count++; } - mutex_unlock(&pool->mutex); + + if (pool->inode && pool->order == 0) + __SetPageMovable(page, pool->inode->i_mapping); + spin_unlock(&pool->lock); return 0; } @@ -82,7 +102,20 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) pool->low_count--; } - list_del(&page->lru); + /* + * We can hit a very rare case (~1/10^9) when the page is being + * isolated exactly at this point. This function is called under + * spin lock so we can't wait here and we have to return NULL + * therefore. + */ + if (!trylock_page(page)) + return NULL; + + clear_bit(ION_PAGE_CACHE, &page->private); + __ClearPageMovable(page); + unlock_page(page); + + list_del_init(&page->lru); return page; } @@ -94,13 +127,13 @@ void *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool) *from_pool = true; - if (mutex_trylock(&pool->mutex)) { - if (pool->high_count) - page = ion_page_pool_remove(pool, true); - else if (pool->low_count) - page = ion_page_pool_remove(pool, false); - mutex_unlock(&pool->mutex); - } + spin_lock(&pool->lock); + if (pool->high_count) + page = ion_page_pool_remove(pool, true); + else if (pool->low_count) + page = ion_page_pool_remove(pool, false); + spin_unlock(&pool->lock); + if (!page) { page = ion_page_pool_alloc_pages(pool); *from_pool = false; @@ -117,13 +150,12 @@ void *ion_page_pool_alloc_pool_only(struct ion_page_pool *pool) BUG_ON(!pool); - if (mutex_trylock(&pool->mutex)) { - if (pool->high_count) - page = ion_page_pool_remove(pool, true); - else if (pool->low_count) - page = ion_page_pool_remove(pool, false); - mutex_unlock(&pool->mutex); - } + spin_lock(&pool->lock); + if (pool->high_count) + page = ion_page_pool_remove(pool, true); + else if (pool->low_count) + page = ion_page_pool_remove(pool, false); + spin_unlock(&pool->lock); return page; } @@ -169,16 +201,24 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, while (freed < nr_to_scan) { struct page *page; - mutex_lock(&pool->mutex); + /* + * If the lock is taken, it's better to let other shrinkers + * do their job, rather than spin here. We'll catch up + * next time. + */ + if (!spin_trylock(&pool->lock)) + break; if (pool->low_count) { page = ion_page_pool_remove(pool, false); } else if (high && pool->high_count) { page = ion_page_pool_remove(pool, true); } else { - mutex_unlock(&pool->mutex); + spin_unlock(&pool->lock); break; } - mutex_unlock(&pool->mutex); + spin_unlock(&pool->lock); + if (!page) + continue; ion_page_pool_free_pages(pool, page); freed += (1 << pool->order); } @@ -186,8 +226,147 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, return ion_page_pool_total(pool, high); } +static bool ion_page_pool_isolate(struct page *page, isolate_mode_t mode) +{ + struct ion_page_pool *pool; + struct address_space *mapping = page_mapping(page); + + VM_BUG_ON_PAGE(PageIsolated(page), page); + + if (!mapping) + return false; + pool = mapping->private_data; + + spin_lock(&pool->lock); + /* could be removed from the cache pool and thus become unmovable */ + if (!__PageMovable(page)) { + spin_unlock(&pool->lock); + return false; + } + + if (unlikely(!test_bit(ION_PAGE_CACHE, &page->private))) { + spin_unlock(&pool->lock); + return false; + } + + list_del(&page->lru); + if (PageHighMem(page)) + pool->high_count--; + else + pool->low_count--; + spin_unlock(&pool->lock); + + return true; +} + +static int ion_page_pool_migrate(struct address_space *mapping, + struct page *newpage, + struct page *page, enum migrate_mode mode) +{ + struct ion_page_pool *pool = mapping->private_data; + + VM_BUG_ON_PAGE(!PageMovable(page), page); + VM_BUG_ON_PAGE(!PageIsolated(page), page); + + if (!trylock_page(page)) + return -EAGAIN; + + spin_lock(&pool->lock); + newpage->private = ION_PAGE_CACHE; + __SetPageMovable(newpage, page_mapping(page)); + get_page(newpage); + __ClearPageMovable(page); + ClearPagePrivate(page); + if (PageHighMem(newpage)) { + list_add_tail(&newpage->lru, &pool->high_items); + pool->high_count++; + } else { + list_add_tail(&newpage->lru, &pool->low_items); + pool->low_count++; + } + spin_unlock(&pool->lock); + + unlock_page(page); + put_page(page); + return 0; +} + +static void ion_page_pool_putback(struct page *page) +{ + /* + * migrate function either succeeds or returns -EAGAIN, which + * results in calling it again until it succeeds, sothis callback + * is not needed. + */ +} + +static struct dentry *ion_pool_do_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + static const struct dentry_operations ops = { + .d_dname = simple_dname, + }; + + return mount_pseudo(fs_type, "ion_pool:", NULL, &ops, 0x77); +} + +static struct file_system_type ion_pool_fs = { + .name = "ion_pool", + .mount = ion_pool_do_mount, + .kill_sb = kill_anon_super, +}; + +static int ion_pool_cnt; +static struct vfsmount *ion_pool_mnt; +static int ion_pool_mount(void) +{ + int ret = 0; + + ion_pool_mnt = kern_mount(&ion_pool_fs); + if (IS_ERR(ion_pool_mnt)) + ret = PTR_ERR(ion_pool_mnt); + + return ret; +} + +static const struct address_space_operations ion_pool_aops = { + .isolate_page = ion_page_pool_isolate, + .migratepage = ion_page_pool_migrate, + .putback_page = ion_page_pool_putback, +}; + +static int ion_pool_register_migration(struct ion_page_pool *pool) +{ + int ret = simple_pin_fs(&ion_pool_fs, &ion_pool_mnt, &ion_pool_cnt); + + if (ret < 0) { + pr_err("Cannot mount pseudo fs: %d\n", ret); + return ret; + } + pool->inode = alloc_anon_inode(ion_pool_mnt->mnt_sb); + if (IS_ERR(pool->inode)) { + ret = PTR_ERR(pool->inode); + pool->inode = NULL; + simple_release_fs(&ion_pool_mnt, &ion_pool_cnt); + return ret; + } + + pool->inode->i_mapping->private_data = pool; + pool->inode->i_mapping->a_ops = &ion_pool_aops; + return 0; +} + +static void ion_pool_unregister_migration(struct ion_page_pool *pool) +{ + if (pool->inode) { + iput(pool->inode); + pool->inode = NULL; + simple_release_fs(&ion_pool_mnt, &ion_pool_cnt); + } +} + struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask, - unsigned int order) + unsigned int order, bool movable) { struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool), GFP_KERNEL); @@ -200,19 +379,24 @@ struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask, INIT_LIST_HEAD(&pool->high_items); pool->gfp_mask = gfp_mask; pool->order = order; - mutex_init(&pool->mutex); + spin_lock_init(&pool->lock); plist_node_init(&pool->list, order); + pool->inode = NULL; + if (movable) + ion_pool_register_migration(pool); + return pool; } void ion_page_pool_destroy(struct ion_page_pool *pool) { + ion_pool_unregister_migration(pool); kfree(pool); } static int __init ion_page_pool_init(void) { - return 0; + return ion_pool_mount(); } device_initcall(ion_page_pool_init); diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index f2f2ca11c3fabaad07c3c579fcf51fdae9824c82..efa6e0fe71f9770ed8a432e9e25e15b115d75697 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -2,7 +2,7 @@ * drivers/staging/android/ion/ion_priv.h * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2016, 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,6 +14,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _ION_PRIV_H #define _ION_PRIV_H @@ -200,8 +205,8 @@ struct ion_heap { struct task_struct *task; int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); - atomic_long_t total_allocated; - atomic_long_t total_handles; + atomic_t total_allocated; + atomic_t total_handles; }; /** @@ -417,11 +422,12 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, * @low_count: number of lowmem items in the pool * @high_items: list of highmem items * @low_items: list of lowmem items - * @mutex: lock protecting this struct and especially the count + * @lock: lock protecting this struct and especially the count * item list * @gfp_mask: gfp_mask to use from alloc * @order: order of pages in the pool * @list: plist node for list of pools + * @inode: inode for ion_pool pseudo filesystem * * Allows you to keep a pool of pre allocated pages to use from your heap. * Keeping a pool of pages that is ready for dma, ie any cached mapping have @@ -433,15 +439,16 @@ struct ion_page_pool { int low_count; struct list_head high_items; struct list_head low_items; - struct mutex mutex; + spinlock_t lock; struct device *dev; gfp_t gfp_mask; unsigned int order; struct plist_node list; + struct inode *inode; }; struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask, - unsigned int order); + unsigned int order, bool movable); void ion_page_pool_destroy(struct ion_page_pool *); void *ion_page_pool_alloc(struct ion_page_pool *, bool *from_pool); void *ion_page_pool_alloc_pool_only(struct ion_page_pool *); diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 2ad4cc7a4785e10f9da6e7861b63a8f0d08f1d6d..016be45727da85db56c1db36091990a05c558c8d 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -14,6 +14,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -766,7 +771,8 @@ static void ion_system_heap_destroy_pools(struct ion_page_pool **pools) * ion_system_heap_destroy_pools to destroy the pools. */ static int ion_system_heap_create_pools(struct device *dev, - struct ion_page_pool **pools) + struct ion_page_pool **pools, + bool movable) { int i; for (i = 0; i < num_orders; i++) { @@ -775,7 +781,8 @@ static int ion_system_heap_create_pools(struct device *dev, if (orders[i]) gfp_flags = high_order_gfp_flags; - pool = ion_page_pool_create(dev, gfp_flags, orders[i]); + pool = ion_page_pool_create(dev, gfp_flags, orders[i], + movable); if (!pool) goto err_create_pool; pools[i] = pool; @@ -814,15 +821,15 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *data) if (!heap->secure_pools[i]) goto err_create_secure_pools; if (ion_system_heap_create_pools( - dev, heap->secure_pools[i])) + dev, heap->secure_pools[i], false)) goto err_create_secure_pools; } } - if (ion_system_heap_create_pools(dev, heap->uncached_pools)) + if (ion_system_heap_create_pools(dev, heap->uncached_pools, false)) goto err_create_uncached_pools; - if (ion_system_heap_create_pools(dev, heap->cached_pools)) + if (ion_system_heap_create_pools(dev, heap->cached_pools, true)) goto err_create_cached_pools; mutex_init(&heap->split_page_mutex); diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 8deee007218bf824cfb29c712f20856542ecd3e2..3feb8587c551ec61a9a0e3764ef3857a3e566646 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -29,6 +29,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -42,8 +47,6 @@ #include #include #include -#include -#include #include #include #include @@ -52,6 +55,7 @@ #define CREATE_TRACE_POINTS #include +#include #ifdef CONFIG_HIGHMEM #define _ZONE ZONE_HIGHMEM @@ -62,6 +66,8 @@ #define CREATE_TRACE_POINTS #include "trace/lowmemorykiller.h" +#include "lowmemorykiller_stats.h" + static uint32_t lowmem_debug_level = 1; static short lowmem_adj[6] = { 0, @@ -90,6 +96,7 @@ static unsigned long lowmem_deathpending_timeout; static unsigned long lowmem_count(struct shrinker *s, struct shrink_control *sc) { + lmk_inc_stats(LMK_COUNT); return global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE) + global_page_state(NR_INACTIVE_ANON) + @@ -156,6 +163,7 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, if (pressure >= 95) { other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - + global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); @@ -169,6 +177,7 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - + global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); @@ -217,24 +226,6 @@ static int test_task_flag(struct task_struct *p, int flag) return 0; } -static int test_task_state(struct task_struct *p, int state) -{ - struct task_struct *t; - - for_each_thread(p, t) { - task_lock(t); - if (t->state & state) { - task_unlock(t); - return 1; - } - task_unlock(t); - } - - return 0; -} - -static DEFINE_MUTEX(scan_mutex); - int can_use_cma_pages(gfp_t gfp_mask) { int can_use = 0; @@ -417,25 +408,16 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) int selected_tasksize = 0; short selected_oom_score_adj; int array_size = ARRAY_SIZE(lowmem_adj); - int other_free; - int other_file; - - if (!mutex_trylock(&scan_mutex)) - return 0; - - other_free = global_page_state(NR_FREE_PAGES); - - if (global_page_state(NR_SHMEM) + total_swapcache_pages() < - global_page_state(NR_FILE_PAGES) + zcache_pages()) - other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - - global_page_state(NR_SHMEM) - - global_page_state(NR_UNEVICTABLE) - - total_swapcache_pages(); - else - other_file = 0; + int other_free = global_page_state(NR_FREE_PAGES); + int other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - + global_page_state(NR_SHMEM) - + global_page_state(NR_UNEVICTABLE) - + total_swapcache_pages(); + other_file = (other_file < 0) ? 0 : other_file; tune_lmk_param(&other_free, &other_file, sc); + lmk_inc_stats(LMK_SCAN); if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) @@ -458,8 +440,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) trace_almk_shrink(0, ret, other_free, other_file, 0); lowmem_print(5, "lowmem_scan %lu, %x, return 0\n", sc->nr_to_scan, sc->gfp_mask); - mutex_unlock(&scan_mutex); - return 0; + trace_lmk_remain_scan(0, sc->nr_to_scan, sc->gfp_mask); + return SHRINK_STOP; } selected_oom_score_adj = min_score_adj; @@ -476,11 +458,17 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) if (test_task_flag(tsk, TIF_MM_RELEASED)) continue; + /* Ignore task if coredump in progress */ + if (tsk->mm && tsk->mm->core_state) + continue; + if (time_before_eq(jiffies, lowmem_deathpending_timeout)) { if (test_task_flag(tsk, TIF_MEMDIE)) { rcu_read_unlock(); - mutex_unlock(&scan_mutex); - return 0; + trace_lmk_remain_scan(0, sc->nr_to_scan, + sc->gfp_mask); + lmk_inc_stats(LMK_TIMEOUT); + return SHRINK_STOP; } } @@ -493,6 +481,17 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) task_unlock(p); continue; } + + if (!thread_group_leader(p) || test_tsk_thread_flag(p, TIF_MEMDIE)) { + lowmem_print(2, "Skipped '%s'(%d), adj %hd, ma %hd\n", + p->comm, p->pid, p->signal->oom_score_adj, + min_score_adj); + task_unlock(p); + if (enable_adaptive_lmk) + atomic_set(&shift_adj, 1); + continue; + } + tasksize = get_mm_rss(p->mm); task_unlock(p); if (tasksize <= 0) @@ -512,17 +511,6 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) } if (selected) { long cache_size, cache_limit, free; - - if (test_task_flag(selected, TIF_MEMDIE) && - (test_task_state(selected, TASK_UNINTERRUPTIBLE))) { - lowmem_print(2, "'%s' (%d) is already killed\n", - selected->comm, - selected->pid); - rcu_read_unlock(); - mutex_unlock(&scan_mutex); - return 0; - } - task_lock(selected); send_sig(SIGKILL, selected, 0); /* @@ -571,20 +559,24 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) lowmem_deathpending_timeout = jiffies + HZ; rem += selected_tasksize; + trace_lmk_sigkill(selected->pid, selected->comm, + selected_oom_score_adj, selected_tasksize, + sc->gfp_mask); rcu_read_unlock(); - /* give the system time to free up the memory */ - msleep_interruptible(20); trace_almk_shrink(selected_tasksize, ret, other_free, other_file, selected_oom_score_adj); + lmk_inc_stats(LMK_KILL); } else { trace_almk_shrink(1, ret, other_free, other_file, 0); + lmk_inc_stats(LMK_WASTE); rcu_read_unlock(); + return SHRINK_STOP; } lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", sc->nr_to_scan, sc->gfp_mask, rem); - mutex_unlock(&scan_mutex); + trace_lmk_remain_scan(rem, sc->nr_to_scan, sc->gfp_mask); return rem; } @@ -599,6 +591,7 @@ static int __init lowmem_init(void) { register_shrinker(&lowmem_shrinker); vmpressure_notifier_register(&lmk_vmpr_nb); + init_procfs_lmk(); return 0; } device_initcall(lowmem_init); diff --git a/drivers/staging/android/lowmemorykiller_stats.c b/drivers/staging/android/lowmemorykiller_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..bda83af6c01fcd96e306dc8c67793f45e96aa72b --- /dev/null +++ b/drivers/staging/android/lowmemorykiller_stats.c @@ -0,0 +1,111 @@ +/* + * lowmemorykiller_stats + * + * Author: Peter Enderborg + * + * 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +/* This code is bookkeeping of statistical information + * from lowmemorykiller and provide a node in proc "/proc/lmkstats". + */ + +#include +#include +#include "lowmemorykiller_stats.h" + +struct lmk_stats { + atomic_long_t scans; /* counter as in shrinker scans */ + atomic_long_t kills; /* the number of sigkills sent */ + atomic_long_t waste; /* the number of expensive calls that did + * not lead to anything + */ + atomic_long_t timeout; /* counter for shrinker calls that needed + * to be cancelled due to pending kills + */ + atomic_long_t count; /* number of shrinker count calls */ + atomic_long_t scan_busy; /* mutex held */ + atomic_long_t no_kill; /* mutex held */ + atomic_long_t busy; + atomic_long_t error; + atomic_long_t unknown; /* internal */ +} st; + +void lmk_inc_stats(int key) +{ + switch (key) { + case LMK_SCAN: + atomic_long_inc(&st.scans); + break; + case LMK_KILL: + atomic_long_inc(&st.kills); + break; + case LMK_WASTE: + atomic_long_inc(&st.waste); + break; + case LMK_TIMEOUT: + atomic_long_inc(&st.timeout); + break; + case LMK_COUNT: + atomic_long_inc(&st.count); + break; + case LMK_BUSY: + atomic_long_inc(&st.busy); + break; + case LMK_ERROR: + atomic_long_inc(&st.error); + break; + case LMK_NO_KILL: + atomic_long_inc(&st.no_kill); + break; + default: + atomic_long_inc(&st.unknown); + break; + } +} + +static int lmk_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "kill: %ld\n", atomic_long_read(&st.kills)); + seq_printf(m, "scan: %ld\n", atomic_long_read(&st.scans)); + seq_printf(m, "waste: %ld\n", atomic_long_read(&st.waste)); + seq_printf(m, "timeout: %ld\n", atomic_long_read(&st.timeout)); + seq_printf(m, "count: %ld\n", atomic_long_read(&st.count)); + seq_printf(m, "busy: %ld\n", atomic_long_read(&st.busy)); + seq_printf(m, "error: %ld\n", atomic_long_read(&st.error)); + seq_printf(m, "no kill: %ld\n", atomic_long_read(&st.no_kill)); + seq_printf(m, "unknown: %ld (internal)\n", + atomic_long_read(&st.unknown)); + + return 0; +} + +static int lmk_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, lmk_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations lmk_proc_fops = { + .open = lmk_proc_open, + .read = seq_read, + .release = single_release +}; + +int __init init_procfs_lmk(void) +{ + proc_create_data(LMK_PROCFS_NAME, 0, NULL, &lmk_proc_fops, NULL); + return 0; +} + +void exit_procfs_lmk(void) +{ + remove_proc_entry(LMK_PROCFS_NAME, NULL); +} diff --git a/drivers/staging/android/lowmemorykiller_stats.h b/drivers/staging/android/lowmemorykiller_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..bfe039e5fcaa58c60f37a0ebf9a0f67098fd2c32 --- /dev/null +++ b/drivers/staging/android/lowmemorykiller_stats.h @@ -0,0 +1,46 @@ +/* + * lowmemorykiller_stats interface + * + * Author: Peter Enderborg + * + * 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. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __LOWMEMORYKILLER_STATS_H +#define __LOWMEMORYKILLER_STATS_H + +enum lmk_kill_stats { + LMK_SCAN = 1, + LMK_KILL = 2, + LMK_WASTE = 3, + LMK_TIMEOUT = 4, + LMK_COUNT = 5, + LMK_SCAN_BUSY = 6, + LMK_NO_KILL = 7, + LMK_BUSY = 8, + LMK_ERROR = 9, + +}; + +#define LMK_PROCFS_NAME "lmkstats" + +#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_STATS +void lmk_inc_stats(int key); +int __init init_procfs_lmk(void); +void exit_procfs_lmk(void); +#else +static inline void lmk_inc_stats(int key) { return; }; +static inline int __init init_procfs_lmk(void) { return 0; }; +static inline void exit_procfs_lmk(void) { return; }; +#endif + +#endif diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index 5fbd3766b981ebb3a3ec962216a48b3432fd35ad..aaa96c3df45b189c9803db1160da1861e42edb5b 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -87,7 +87,7 @@ static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence) int status = 1; struct sync_timeline *parent = sync_pt_parent(pt); - if (test_bit(FENCE_FLAG_SIGNALED_BIT, &pt->base.flags)) + if (fence_is_signaled_locked(&pt->base)) status = pt->base.status; seq_printf(s, " %s%spt %s", diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 8fed55342b0f63721c837d2765d2476dedcbe011..7b4af519e17e1a92e9b6d594ea95fad753af5a36 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -2911,7 +2911,6 @@ static int __init comedi_init(void) dev = comedi_alloc_board_minor(NULL); if (IS_ERR(dev)) { comedi_cleanup_board_minors(); - class_destroy(comedi_class); cdev_del(&comedi_cdev); unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c index 2a50cf957101116f27a14b76ee1364f030ec1efb..7397d239b65aa09dccdc3e4a6b3423ec408c0b1c 100644 --- a/drivers/staging/fbtft/fb_agm1264k-fl.c +++ b/drivers/staging/fbtft/fb_agm1264k-fl.c @@ -13,6 +13,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c index a6b43323f29ac952d98c5812fd1e7cbb9b002ce7..c5683a8b4fc08cf08fea382b641af90c84e85921 100644 --- a/drivers/staging/fbtft/fb_pcd8544.c +++ b/drivers/staging/fbtft/fb_pcd8544.c @@ -16,6 +16,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c index b167c50616318a94e98c766c9ef972f05fc60fbc..7d71872d7215b95ac61e583851e6d73d56453893 100644 --- a/drivers/staging/fbtft/fb_ra8875.c +++ b/drivers/staging/fbtft/fb_ra8875.c @@ -12,6 +12,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/staging/fbtft/fb_ssd1306.c b/drivers/staging/fbtft/fb_ssd1306.c index e0b34a42c9c635bd243737291dc8bf02ef831861..332543083a80ee2e4859a4a1aacee39607bb4b94 100644 --- a/drivers/staging/fbtft/fb_ssd1306.c +++ b/drivers/staging/fbtft/fb_ssd1306.c @@ -13,6 +13,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/staging/fbtft/fb_tls8204.c b/drivers/staging/fbtft/fb_tls8204.c index 2183f98c831514c9eef828c3ef8bbceabb47fd7a..f3b98f7fa4ccbe4f7a3f8e225007b2be6b72c424 100644 --- a/drivers/staging/fbtft/fb_tls8204.c +++ b/drivers/staging/fbtft/fb_tls8204.c @@ -17,6 +17,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/staging/fbtft/fb_uc1611.c b/drivers/staging/fbtft/fb_uc1611.c index 4e828142058ef6c5e8ae2a714f7aad8c9f41a703..dd25d72efb96fe348963ba34817cc3f9d0fcd248 100644 --- a/drivers/staging/fbtft/fb_uc1611.c +++ b/drivers/staging/fbtft/fb_uc1611.c @@ -15,6 +15,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/staging/fbtft/fb_uc1701.c b/drivers/staging/fbtft/fb_uc1701.c index 212908e3927727badbe5359d8996ce63dcd0f5be..10f4191cdc42a5f1e972f6f5ff5769bb5947c3cc 100644 --- a/drivers/staging/fbtft/fb_uc1701.c +++ b/drivers/staging/fbtft/fb_uc1701.c @@ -16,6 +16,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c index f8cb610a7b6984cb3bc977cf52f63966f6748620..3b6e57bf38a9a4c135fd1c5c3e75c52db5e1a7b9 100644 --- a/drivers/staging/fbtft/fb_watterott.c +++ b/drivers/staging/fbtft/fb_watterott.c @@ -13,6 +13,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c index 58449ad84f46c17f842cc32e04ee5c18cf2b58c0..097db4118a219a18f9ec17777fbfd08d7c8fbad3 100644 --- a/drivers/staging/fbtft/fbtft-bus.c +++ b/drivers/staging/fbtft/fbtft-bus.c @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 18c2b6daf58857e1d1f34462d5e95a4e5e1d1178..4005ee42b464fe867bb0885962272ef4e729866e 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -15,6 +15,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c index 6eb600ff70569ef6ceb902afcc49ddce08b09953..d433cd6efbd6034a278b2d6fc7256fe7cae5eca5 100644 --- a/drivers/staging/iio/iio_simple_dummy_events.c +++ b/drivers/staging/iio/iio_simple_dummy_events.c @@ -7,6 +7,11 @@ * * Event handling elements of industrial I/O reference driver. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index f35ee85f61b582f9b6014e009a4e6383f18e2c0e..01e642db311e5cc4d977ab262c6c912dbe23351b 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -529,9 +529,6 @@ static int vnt_start(struct ieee80211_hw *hw) goto free_all; } - if (vnt_key_init_table(priv)) - goto free_all; - priv->int_interval = 1; /* bInterval is set to 1 */ vnt_int_start_interrupt(priv); diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index a180c000e246ce2423482672c5ee9ef02a687406..200d3de8bc1e8a8303d3169813d957f1732206d8 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1112,18 +1112,6 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, */ if (dump_payload) goto after_immediate_data; - /* - * Check for underflow case where both EDTL and immediate data payload - * exceeds what is presented by CDB's TRANSFER LENGTH, and what has - * already been set in target_cmd_size_check() as se_cmd->data_length. - * - * For this special case, fail the command and dump the immediate data - * payload. - */ - if (cmd->first_burst_len > cmd->se_cmd.data_length) { - cmd->sense_reason = TCM_INVALID_CDB_FIELD; - goto after_immediate_data; - } immed_ret = iscsit_handle_immediate_data(cmd, hdr, cmd->first_burst_len); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 272e6f755322cac55bc0992f3437bc4b851a0814..253a91bff9439f48d9a1632c230006f9ac59cce5 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -132,7 +132,7 @@ int init_se_kmem_caches(void); void release_se_kmem_caches(void); u32 scsi_get_new_index(scsi_index_t); void transport_subsystem_check_init(void); -int transport_cmd_finish_abort(struct se_cmd *, int); +void transport_cmd_finish_abort(struct se_cmd *, int); unsigned char *transport_dump_cmd_direction(struct se_cmd *); void transport_dump_dev_state(struct se_device *, char *, int *); void transport_dump_dev_info(struct se_device *, struct se_lun *, diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index c9be953496ec09e66bd27d9ec7e860816c5a2320..46b1991fbb500d25ee85a273a6668546260316dc 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -75,7 +75,7 @@ void core_tmr_release_req(struct se_tmr_req *tmr) kfree(tmr); } -static int core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) +static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) { unsigned long flags; bool remove = true, send_tas; @@ -91,7 +91,7 @@ static int core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) transport_send_task_abort(cmd); } - return transport_cmd_finish_abort(cmd, remove); + transport_cmd_finish_abort(cmd, remove); } static int target_check_cdb_and_preempt(struct list_head *list, @@ -185,8 +185,8 @@ void core_tmr_abort_task( cancel_work_sync(&se_cmd->work); transport_wait_for_tasks(se_cmd); - if (!transport_cmd_finish_abort(se_cmd, true)) - target_put_sess_cmd(se_cmd); + transport_cmd_finish_abort(se_cmd, true); + target_put_sess_cmd(se_cmd); printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" " ref_tag: %llu\n", ref_tag); @@ -286,8 +286,8 @@ static void core_tmr_drain_tmr_list( cancel_work_sync(&cmd->work); transport_wait_for_tasks(cmd); - if (!transport_cmd_finish_abort(cmd, 1)) - target_put_sess_cmd(cmd); + transport_cmd_finish_abort(cmd, 1); + target_put_sess_cmd(cmd); } } @@ -385,8 +385,8 @@ static void core_tmr_drain_state_list( cancel_work_sync(&cmd->work); transport_wait_for_tasks(cmd); - if (!core_tmr_handle_tas_abort(cmd, tas)) - target_put_sess_cmd(cmd); + core_tmr_handle_tas_abort(cmd, tas); + target_put_sess_cmd(cmd); } } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 37c77db6e7372a7c8ccb0825d303cfd673314ab7..60743bf27f3782d02dc61441674c8105c4ed37e5 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -639,10 +639,9 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) percpu_ref_put(&lun->lun_ref); } -int transport_cmd_finish_abort(struct se_cmd *cmd, int remove) +void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) { bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF); - int ret = 0; if (cmd->se_cmd_flags & SCF_SE_LUN_CMD) transport_lun_remove_cmd(cmd); @@ -654,11 +653,9 @@ int transport_cmd_finish_abort(struct se_cmd *cmd, int remove) cmd->se_tfo->aborted_task(cmd); if (transport_cmd_check_stop_to_fabric(cmd)) - return 1; + return; if (remove && ack_kref) - ret = transport_put_cmd(cmd); - - return ret; + transport_put_cmd(cmd); } static void target_complete_failure_work(struct work_struct *work) diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c index ead9765666c84aae5d2dd89850822a70f28a01ae..ab25987676fcc3d44638c7f843436cff7bee371c 100644 --- a/drivers/thermal/msm_thermal-dev.c +++ b/drivers/thermal/msm_thermal-dev.c @@ -100,6 +100,16 @@ static long validate_and_copy(unsigned int *cmd, unsigned long *arg, goto validate_exit; } break; + case MSM_THERMAL_GET_CLUSTER_FREQUENCY_PLAN: + if (query->clock_freq.cluster_num >= NR_CPUS) { + ret = -EINVAL; + goto validate_exit; + } + case MSM_THERMAL_GET_CLUSTER_VOLTAGE_PLAN: + if (query->voltage.cluster_num >= NR_CPUS) { + ret = -EINVAL; + goto validate_exit; + } default: break; } diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index 50d1619d7bc3a3929c3f8d54271749a02f2fa4d3..b1f4c3f27111099d2b09753780ce9dcf88dd2a96 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -200,7 +200,6 @@ static bool cluster_info_probed; static bool cluster_info_nodes_called; static bool in_suspend, retry_in_progress; static bool lmh_dcvs_available; -static bool lmh_dcvs_is_supported; static int *tsens_id_map; static int *zone_id_tsens_map; static DEFINE_MUTEX(vdd_rstr_mutex); @@ -996,7 +995,7 @@ static int msm_thermal_cpufreq_callback(struct notifier_block *nfb, switch (event) { case CPUFREQ_ADJUST: - max_freq_req = (lmh_dcvs_is_supported) ? UINT_MAX : + max_freq_req = (lmh_dcvs_available) ? UINT_MAX : cpus[policy->cpu].parent_ptr->limited_max_freq; min_freq_req = cpus[policy->cpu].parent_ptr->limited_min_freq; pr_debug("mitigating CPU%d to freq max: %u min: %u\n", @@ -2859,7 +2858,7 @@ static void msm_thermal_bite(int zone_id, int temp) tsens_id, temp); } /* If it is a secure device ignore triggering the thermal bite. */ - if (!scm_is_secure_device()) + if (scm_is_secure_device()) return; if (!is_scm_armv8()) { scm_call_atomic1(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, 0); @@ -5380,7 +5379,7 @@ int msm_thermal_init(struct msm_thermal_data *pdata) if (ret) pr_err("cannot register cpufreq notifier. err:%d\n", ret); - if (!lmh_dcvs_is_supported) { + if (!lmh_dcvs_available) { register_reboot_notifier(&msm_thermal_reboot_notifier); pm_notifier(msm_thermal_suspend_callback, 0); } @@ -7415,7 +7414,6 @@ static int msm_thermal_dev_probe(struct platform_device *pdev) if (ret) goto probe_exit; - lmh_dcvs_is_supported = of_property_read_bool(node, "clock-names"); probe_cc(node, &data, pdev); probe_freq_mitigation(node, &data, pdev); probe_cx_phase_ctrl(node, &data, pdev); diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c index 2df1bf69e7c9170ba30f7d5ba7eec0c5d415aa99..62a261232236d23d47aafe4243539a694ad7642e 100644 --- a/drivers/thermal/qpnp-adc-tm.c +++ b/drivers/thermal/qpnp-adc-tm.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -1699,7 +1704,12 @@ static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal, return -EINVAL; } - rc = qpnp_adc_tm_scale_voltage_therm_pu2(chip->vadc_dev, + if (adc_tm_sensor->btm_channel_num == QPNP_ADC_TM_M1_ADC_CH_SEL_CTL || + adc_tm_sensor->btm_channel_num == QPNP_ADC_TM_M2_ADC_CH_SEL_CTL) + rc = qpnp_adc_tm_scale_voltage_therm_pu2_decidegc(chip->vadc_dev, + chip->adc->adc_prop, reg, &result); + else + rc = qpnp_adc_tm_scale_voltage_therm_pu2(chip->vadc_dev, chip->adc->adc_prop, reg, &result); if (rc < 0) { pr_err("Failed to lookup the therm thresholds\n"); @@ -1744,8 +1754,13 @@ static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal, pr_debug("requested a high - %d and low - %d with trip - %d\n", tm_config.high_thr_temp, tm_config.low_thr_temp, trip); - rc = qpnp_adc_tm_scale_therm_voltage_pu2(chip->vadc_dev, - chip->adc->adc_prop, &tm_config); + if (adc_tm->btm_channel_num == QPNP_ADC_TM_M1_ADC_CH_SEL_CTL || + adc_tm->btm_channel_num == QPNP_ADC_TM_M2_ADC_CH_SEL_CTL) + rc = qpnp_adc_tm_scale_therm_voltage_pu2_decidegc(chip->vadc_dev, + chip->adc->adc_prop, &tm_config); + else + rc = qpnp_adc_tm_scale_therm_voltage_pu2(chip->vadc_dev, + chip->adc->adc_prop, &tm_config); if (rc < 0) { pr_err("Failed to lookup the adc-tm thresholds\n"); return rc; diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 416006a3384cebb31acdf12a34d82c96a16f47c0..830ef92ffe80ae29940c33f421d897fce4dd489a 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -218,7 +218,6 @@ struct msm_hs_wakeup { }; struct msm_hs_port { - bool startup_locked; struct uart_port uport; unsigned long imr_reg; /* shadow value of UARTDM_IMR */ struct clk *clk; @@ -273,7 +272,7 @@ static struct of_device_id msm_hs_match_table[] = { #define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE #define UARTDM_RX_BUF_SIZE 512 #define RETRY_TIMEOUT 5 -#define UARTDM_NR 4 +#define UARTDM_NR 256 #define BAM_PIPE_MIN 0 #define BAM_PIPE_MAX 11 #define BUS_SCALING 1 @@ -293,8 +292,6 @@ static struct msm_hs_port *msm_hs_get_hs_port(int port_index); static void msm_hs_queue_rx_desc(struct msm_hs_port *msm_uport); static int disconnect_rx_endpoint(struct msm_hs_port *msm_uport); static int msm_hs_pm_resume(struct device *dev); -static void msm_hs_pm_suspend(struct device *dev); - #define UARTDM_TO_MSM(uart_port) \ container_of((uart_port), struct msm_hs_port, uport) @@ -395,8 +392,6 @@ static void msm_hs_resource_unvote(struct msm_hs_port *msm_uport) { struct uart_port *uport = &(msm_uport->uport); int rc = atomic_read(&msm_uport->resource_count); - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; MSM_HS_DBG("%s(): power usage count %d", __func__, rc); if (rc <= 0) { @@ -405,15 +400,8 @@ static void msm_hs_resource_unvote(struct msm_hs_port *msm_uport) return; } atomic_dec(&msm_uport->resource_count); - - if (pm_runtime_enabled(uport->dev)) { - pm_runtime_mark_last_busy(uport->dev); - pm_runtime_put_autosuspend(uport->dev); - } else { - MSM_HS_DBG("%s():tx.flush:%d,in_flight:%d,rx.flush:%d\n", - __func__, tx->flush, tx->dma_in_flight, rx->flush); - msm_hs_pm_suspend(uport->dev); - } + pm_runtime_mark_last_busy(uport->dev); + pm_runtime_put_autosuspend(uport->dev); } /* Vote for resources before accessing them */ @@ -597,8 +585,6 @@ static void hex_dump_ipc(struct msm_hs_port *msm_uport, void *ipc_ctx, char buf[(BUF_DUMP_SIZE * 3) + 2]; int len = 0; - if (msm_uport->ipc_debug_mask == FATAL_LEV) - return; len = min(size, BUF_DUMP_SIZE); /* * Print upto 32 data bytes, 32 bytes per line, 1 byte at a time and @@ -649,7 +635,6 @@ static int msm_serial_loopback_enable_set(void *data, u64 val) unsigned long flags; int ret = 0; - msm_uport->startup_locked = true; msm_hs_resource_vote(msm_uport); if (val) { @@ -669,7 +654,7 @@ static int msm_serial_loopback_enable_set(void *data, u64 val) } /* Calling CLOCK API. Hence mb() requires here. */ mb(); - msm_uport->startup_locked = false; + msm_hs_resource_unvote(msm_uport); return 0; } @@ -681,13 +666,11 @@ static int msm_serial_loopback_enable_get(void *data, u64 *val) unsigned long flags; int ret = 0; - msm_uport->startup_locked = true; msm_hs_resource_vote(msm_uport); spin_lock_irqsave(&uport->lock, flags); ret = msm_hs_read(&msm_uport->uport, UART_DM_MR2); spin_unlock_irqrestore(&uport->lock, flags); - msm_uport->startup_locked = false; msm_hs_resource_unvote(msm_uport); @@ -845,11 +828,6 @@ static int msm_hs_spsconnect_rx(struct uart_port *uport) struct sps_register_event *sps_event = &rx->prod.event; unsigned long flags; - if (msm_uport->rx.pending_flag) { - MSM_HS_WARN("%s(): Buffers may be pending 0x%lx", - __func__, msm_uport->rx.pending_flag); - } - /* Establish connection between peripheral and memory endpoint */ ret = sps_connect(sps_pipe_handle, sps_config); if (ret) { @@ -865,6 +843,9 @@ static int msm_hs_spsconnect_rx(struct uart_port *uport) goto reg_event_err; } spin_lock_irqsave(&uport->lock, flags); + if (msm_uport->rx.pending_flag) + MSM_HS_WARN("%s(): Buffers may be pending 0x%lx", + __func__, msm_uport->rx.pending_flag); msm_uport->rx.queued_flag = 0; msm_uport->rx.pending_flag = 0; msm_uport->rx.rx_inx = 0; @@ -1303,8 +1284,6 @@ static int disconnect_rx_endpoint(struct msm_hs_port *msm_uport) int ret = 0; ret = sps_rx_disconnect(sps_pipe_handle); - if (ret) - MSM_HS_ERR("%s(): sps_disconnect failed\n", __func__); if (msm_uport->rx.pending_flag) MSM_HS_WARN("%s(): Buffers may be pending 0x%lx", @@ -1314,6 +1293,8 @@ static int disconnect_rx_endpoint(struct msm_hs_port *msm_uport) msm_uport->rx.pending_flag = 0; msm_uport->rx.rx_inx = 0; + if (ret) + MSM_HS_ERR("%s(): sps_disconnect failed\n", __func__); msm_uport->rx.flush = FLUSH_SHUTDOWN; MSM_HS_DBG("%s: Calling Completion\n", __func__); wake_up(&msm_uport->bam_disconnect_wait); @@ -1371,14 +1352,9 @@ static void msm_hs_stop_rx_locked(struct uart_port *uport) { struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - if (msm_uport->pm_state != MSM_HS_PM_ACTIVE) { + if (msm_uport->pm_state != MSM_HS_PM_ACTIVE) MSM_HS_WARN("%s(): Clocks are off\n", __func__); - /* Make sure resource_on doesn't get called */ - if (msm_hs_clk_bus_vote(msm_uport)) - MSM_HS_ERR("%s:Failed clock vote\n", __func__); - msm_hs_disable_rx(uport); - msm_hs_clk_bus_unvote(msm_uport); - } else + else msm_hs_disable_rx(uport); if (msm_uport->rx.flush == FLUSH_NONE) @@ -1388,19 +1364,11 @@ static void msm_hs_stop_rx_locked(struct uart_port *uport) static void msm_hs_disconnect_rx(struct uart_port *uport) { struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct msm_hs_rx *rx = &msm_uport->rx; - struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle; - u32 prod_empty = 0; msm_hs_disable_rx(uport); /* Disconnect the BAM RX pipe */ if (msm_uport->rx.flush == FLUSH_NONE) msm_uport->rx.flush = FLUSH_STOP; - - if (sps_is_pipe_empty(sps_pipe_handle, &prod_empty)) { - MSM_HS_WARN("%s():Pipe Not Empty, ret=%d, flush=%d\n", - __func__, prod_empty, msm_uport->rx.flush); - } disconnect_rx_endpoint(msm_uport); MSM_HS_DBG("%s(): rx->flush %d", __func__, msm_uport->rx.flush); } @@ -1421,8 +1389,6 @@ void tx_timeout_handler(unsigned long arg) if (UARTDM_ISR_CURRENT_CTS_BMSK & isr) MSM_HS_WARN("%s(): CTS Disabled, ISR 0x%x", __func__, isr); dump_uart_hs_registers(msm_uport); - /* Stop further loging */ - MSM_HS_ERR("%s(): Stop IPC logging\n", __func__); } /* Transmit the next chunk of data */ @@ -1866,27 +1832,11 @@ static void msm_hs_start_tx_locked(struct uart_port *uport) { struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); struct msm_hs_tx *tx = &msm_uport->tx; - unsigned int isr; - - if (msm_uport->startup_locked) { - MSM_HS_DBG("%s(): No Tx Request, startup_locked=%d\n", - __func__, msm_uport->startup_locked); - return; - } /* Bail if transfer in progress */ if (tx->flush < FLUSH_STOP || tx->dma_in_flight) { MSM_HS_INFO("%s(): retry, flush %d, dma_in_flight %d\n", __func__, tx->flush, tx->dma_in_flight); - - if (msm_uport->pm_state == MSM_HS_PM_ACTIVE) { - isr = msm_hs_read(uport, UART_DM_ISR); - if (UARTDM_ISR_CURRENT_CTS_BMSK & isr) - MSM_HS_DBG("%s():CTS 1: Peer is Busy, ISR 0x%x", - __func__, isr); - } else - MSM_HS_WARN("%s(): Clocks are off\n", __func__); - return; } @@ -2305,7 +2255,7 @@ void disable_wakeup_interrupt(struct msm_hs_port *msm_uport) return; if (msm_uport->wakeup.enabled) { - disable_irq(msm_uport->wakeup.irq); + disable_irq_nosync(msm_uport->wakeup.irq); enable_irq(uport->irq); spin_lock_irqsave(&uport->lock, flags); msm_uport->wakeup.enabled = false; @@ -2319,34 +2269,16 @@ void msm_hs_resource_off(struct msm_hs_port *msm_uport) { struct uart_port *uport = &(msm_uport->uport); unsigned int data; - int ret = 0; MSM_HS_DBG("%s(): begin", __func__); msm_hs_disable_flow_control(uport, false); if (msm_uport->rx.flush == FLUSH_NONE) msm_hs_disconnect_rx(uport); - else if (msm_uport->rx.flush != FLUSH_SHUTDOWN) { - MSM_HS_WARN("%s():Rx Flush=%d Not Expected\n", - __func__, msm_uport->rx.flush); - /* disable and disconnect rx */ - ret = wait_event_timeout(msm_uport->rx.wait, - !msm_uport->rx.pending_flag, 500); - if (!ret) - MSM_HS_WARN("%s(): rx disconnect not complete", - __func__); - msm_hs_disconnect_rx(uport); - } else - MSM_HS_DBG("%s():Rx Flush=%d In Proper State\n", - __func__, msm_uport->rx.flush); /* disable dlink */ - if (msm_uport->tx.flush == FLUSH_NONE) { - ret = wait_event_timeout(msm_uport->tx.wait, + if (msm_uport->tx.flush == FLUSH_NONE) + wait_event_timeout(msm_uport->tx.wait, msm_uport->tx.flush == FLUSH_STOP, 500); - if (!ret) - MSM_HS_WARN("%s(): tx disconnect not complete", - __func__); - } if (msm_uport->tx.flush != FLUSH_SHUTDOWN) { data = msm_hs_read(uport, UART_DM_DMEN); @@ -2364,29 +2296,21 @@ void msm_hs_resource_on(struct msm_hs_port *msm_uport) unsigned int data; unsigned long flags; - if (msm_uport->startup_locked) { - MSM_HS_WARN("%s(): startup_locked=%d\n", - __func__, msm_uport->startup_locked); - return; - } - if (msm_uport->rx.flush == FLUSH_SHUTDOWN || msm_uport->rx.flush == FLUSH_STOP) { msm_hs_write(uport, UART_DM_CR, RESET_RX); data = msm_hs_read(uport, UART_DM_DMEN); data |= UARTDM_RX_BAM_ENABLE_BMSK; msm_hs_write(uport, UART_DM_DMEN, data); - } else - MSM_HS_DBG("%s():rx.flush=%d, Rx is not enabled\n", - __func__, msm_uport->rx.flush); + } + msm_hs_spsconnect_tx(msm_uport); if (msm_uport->rx.flush == FLUSH_SHUTDOWN) { msm_hs_spsconnect_rx(uport); spin_lock_irqsave(&uport->lock, flags); msm_hs_start_rx_locked(uport); spin_unlock_irqrestore(&uport->lock, flags); } - msm_hs_spsconnect_tx(msm_uport); } /* Request to turn off uart clock once pending TX is flushed */ @@ -2679,7 +2603,6 @@ static int msm_hs_startup(struct uart_port *uport) struct sps_pipe *sps_pipe_handle_tx = tx->cons.pipe_handle; struct sps_pipe *sps_pipe_handle_rx = rx->prod.pipe_handle; - msm_uport->startup_locked = true; rfr_level = uport->fifosize; if (rfr_level > 16) rfr_level -= 16; @@ -2691,7 +2614,8 @@ static int msm_hs_startup(struct uart_port *uport) msm_hs_resource_vote(msm_uport); if (is_use_low_power_wakeup(msm_uport)) { - ret = request_irq(msm_uport->wakeup.irq, msm_hs_wakeup_isr, + ret = request_threaded_irq(msm_uport->wakeup.irq, NULL, + msm_hs_wakeup_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "msm_hs_wakeup", msm_uport); if (unlikely(ret)) { @@ -2731,9 +2655,6 @@ static int msm_hs_startup(struct uart_port *uport) flush_kthread_worker(&msm_uport->rx.kworker); if (rx->flush != FLUSH_SHUTDOWN) disconnect_rx_endpoint(msm_uport); - else - MSM_HS_DBG("%s(): Rx Flush=%d In Proper state\n", - __func__, rx->flush); ret = msm_hs_spsconnect_rx(uport); if (ret) { MSM_HS_ERR("msm_serial_hs: SPS connect failed for RX"); @@ -2809,7 +2730,6 @@ static int msm_hs_startup(struct uart_port *uport) atomic_set(&msm_uport->client_req_state, 0); LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt, "%s: Client_Count 0\n", __func__); - msm_uport->startup_locked = false; msm_hs_start_rx_locked(uport); spin_unlock_irqrestore(&uport->lock, flags); @@ -3238,8 +3158,6 @@ static void msm_hs_pm_suspend(struct device *dev) msm_uport->pm_state = MSM_HS_PM_SUSPENDED; msm_hs_resource_off(msm_uport); obs_manage_irq(msm_uport, false); - if (!atomic_read(&msm_uport->client_req_state)) - enable_wakeup_interrupt(msm_uport); msm_hs_clk_bus_unvote(msm_uport); /* For OBS, don't use wakeup interrupt, set gpio to suspended state */ @@ -3251,6 +3169,8 @@ static void msm_hs_pm_suspend(struct device *dev) __func__); } + if (!atomic_read(&msm_uport->client_req_state)) + enable_wakeup_interrupt(msm_uport); LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt, "%s: PM State Suspended client_count %d\n", __func__, client_count); @@ -3772,14 +3692,9 @@ static void msm_hs_shutdown(struct uart_port *uport) MSM_HS_WARN("%s(): rx disconnect not complete", __func__); msm_hs_disconnect_rx(uport); - } else { - MSM_HS_DBG("%s(): Rx Flush is in Proper state=%d\n", - __func__, msm_uport->rx.flush); } - if (cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work)) - MSM_HS_DBG("%s(): Work was pending, canceled it\n", - __func__); + cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work); flush_workqueue(msm_uport->hsuart_wq); /* BAM Disconnect for TX */ diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e4f69bddcfb1e10ed261236ec6b67b229a8f4a78..5ab54ef4f30428f72fc22d694f176ef126416dfd 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2708,13 +2708,13 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) * related to the kernel should not use this. */ data = vt_get_shift_state(); - ret = put_user(data, p); + ret = __put_user(data, p); break; case TIOCL_GETMOUSEREPORTING: console_lock(); /* May be overkill */ data = mouse_reporting(); console_unlock(); - ret = put_user(data, p); + ret = __put_user(data, p); break; case TIOCL_SETVESABLANK: console_lock(); @@ -2723,7 +2723,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) break; case TIOCL_GETKMSGREDIRECT: data = vt_get_kmsg_redirect(); - ret = put_user(data, p); + ret = __put_user(data, p); break; case TIOCL_SETKMSGREDIRECT: if (!capable(CAP_SYS_ADMIN)) { diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 72d1109f13ebdbcb6d55bcb2615f33675f4b941d..8c579700255adbde442fcd51d3138896233c8734 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -16,6 +16,11 @@ * (C) Copyright Greg Kroah-Hartman 2002-2003 * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -23,6 +28,10 @@ #include #include "usb.h" +#ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION +#include +#endif + static inline const char *plural(int n) { return (n == 1 ? "" : "s"); @@ -168,10 +177,14 @@ int usb_choose_configuration(struct usb_device *udev) best = c; } - if (insufficient_power > 0) + if (insufficient_power > 0) { dev_info(&udev->dev, "rejected %d configuration%s " "due to insufficient available bus power\n", insufficient_power, plural(insufficient_power)); +#ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION + host_send_uevent(USB_HOST_EXT_EVENT_INSUFFICIENT_POWER); +#endif + } if (best) { /* choose usb audio class preferred config if available */ diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 3116edfcdc18558aa768d248f1ff1881448ced09..96b21b0dac1e8c15fb20c19c85d13a58ab95b285 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -223,10 +223,6 @@ static const struct usb_device_id usb_quirk_list[] = { /* Blackmagic Design UltraStudio SDI */ { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, - /* Hauppauge HVR-950q */ - { USB_DEVICE(0x2040, 0x7200), .driver_info = - USB_QUIRK_CONFIG_INTF_STRINGS }, - /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 5a42c459040295a98c286ca993f9468a054682ca..500cbe6652d9f0e4634e0ef61b844219cdb0d9c3 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -104,4 +104,13 @@ config USB_DWC3_QCOM Recent Qualcomm SoCs ship with one DesignWare Core USB3 IP inside, say 'Y' or 'M' if you have one such device. +config USB_DWC3_MSM_ID_POLL + bool "Support ID polling function on DesignWare USB Controller for MSM" + depends on USB_DWC3_DUAL_ROLE + depends on USB_DWC3 + default n + help + Say Y here to enable the ID polling function on the DesignWare USB3.0 + (DRD) Controller for MSM driver. + endif diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 0744b14e120b75ca0bb37bcc53ee5f4c63d3dc8e..c2eba06f2acec2a97a25f93d2c4beabbcb1bc993 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1333,6 +1333,8 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_event_buffers_cleanup(dwc); dwc3_free_event_buffers(dwc); + usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy, 1); phy_power_off(dwc->usb2_generic_phy); phy_power_off(dwc->usb3_generic_phy); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 927c84ea4921bce63c7c392b0f3e6b4b7876ed1b..1b4fb562ce4ba4f5347fcf191b85b0aa28d2ab84 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -39,7 +39,6 @@ #define DWC3_MSG_MAX 500 /* Global constants */ -#define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */ #define DWC3_EP0_BOUNCE_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 #define DWC3_XHCI_RESOURCES_NUM 2 @@ -749,7 +748,6 @@ struct dwc3_scratchpad_array { * @ctrl_req: usb control request which is used for ep0 * @ep0_trb: trb which is used for the ctrl_req * @ep0_bounce: bounce buffer for ep0 - * @zlp_buf: used when request->zero is set * @setup_buf: used while precessing STD USB requests * @ctrl_req_addr: dma address of ctrl_req * @ep0_trb: dma address of ep0_trb @@ -855,7 +853,6 @@ struct dwc3 { struct usb_ctrlrequest *ctrl_req; struct dwc3_trb *ep0_trb; void *ep0_bounce; - void *zlp_buf; void *scratchbuf; u8 *setup_buf; dma_addr_t ctrl_req_addr; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 3c0f68deee3421daeb2dc48d66bfe6fd5b6e704a..eeb855dbdd4af0ccfe11181595c4a3ceebe173b2 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -39,6 +44,9 @@ #include #include #include +#ifdef CONFIG_USB_DWC3_MSM_ID_POLL +#include +#endif /* CONFIG_USB_DWC3_MSM_ID_POLL */ #include #include #include @@ -46,6 +54,11 @@ #include #include #include +#ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION +#include +#endif +#include +#include #include "power.h" #include "core.h" @@ -54,8 +67,6 @@ #include "debug.h" #include "xhci.h" -#define SDP_CONNETION_CHECK_TIME 10000 /* in ms */ - /* time out to wait for USB cable status notification (in ms)*/ #define SM_INIT_TIMEOUT 30000 @@ -72,8 +83,6 @@ MODULE_PARM_DESC(cpu_to_affin, "affin usb irq to this cpu"); /* XHCI registers */ #define USB3_HCSPARAMS1 (0x4) -#define USB3_HCCPARAMS2 (0x1c) -#define HCC_CTC(p) ((p) & (1 << 3)) #define USB3_PORTSC (0x420) /** @@ -146,6 +155,7 @@ enum plug_orientation { #define ID 0 #define B_SESS_VLD 1 #define B_SUSPEND 2 +#define A_VBUS_DROP_DET 3 #define PM_QOS_SAMPLE_SEC 2 #define PM_QOS_THRESHOLD 400 @@ -215,12 +225,13 @@ struct dwc3_msm { struct notifier_block dwc3_cpu_notifier; struct notifier_block usbdev_nb; bool hc_died; - bool xhci_ss_compliance_enable; struct extcon_dev *extcon_vbus; struct extcon_dev *extcon_id; + struct extcon_dev *extcon_vbus_drop; struct notifier_block vbus_nb; struct notifier_block id_nb; + struct notifier_block vbus_drop_nb; struct notifier_block host_nb; @@ -232,8 +243,29 @@ struct dwc3_msm { int pm_qos_latency; struct pm_qos_request pm_qos_req_dma; struct delayed_work perf_vote_work; - struct delayed_work sdp_check; - struct mutex suspend_resume_mutex; + +#ifdef CONFIG_USB_DWC3_MSM_ID_POLL + /* id polling */ + bool id_polling_use; + bool id_polling_start; + struct delayed_work id_polling_work; + struct workqueue_struct *id_polling_q; + unsigned int id_polling_up_interval; + unsigned int id_polling_up_period; + int id_polling_pd_gpio; + struct qpnp_vadc_chip *usb_detect_adc; + spinlock_t id_polling_lock; + bool otg_present; + unsigned int lcd_blanked; + struct wakeup_source id_polling_wu; + struct delayed_work setsink_work; + struct wake_lock setsink_lock; + int setsink_cnt; +#ifdef CONFIG_FB + struct notifier_block fb_notif; +#endif /* CONFIG_FB */ +#endif /* CONFIG_USB_DWC3_MSM_ID_POLL */ + bool send_vbus_drop_ue; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -250,6 +282,17 @@ struct dwc3_msm { #define DSTS_CONNECTSPD_SS 0x4 +#ifdef CONFIG_USB_DWC3_MSM_ID_POLL +#define USB_ID_POLLING_UP_INTERVAL 1000 /* s */ +#define USB_ID_POLLING_UP_PERIOD 100 /* us */ +#define USB_ID_POLLING_WAKE_TIMEOUT 2000 + +#define SETSINK_RETRY_INTERVAL 2000 +#define WAKELOCK_RETRY_INTERVAL 2500 + +/* Max of retry to set SINK */ +#define SETSINK_RETRY_MAX 3 +#endif /* CONFIG_USB_DWC3_MSM_ID_POLL */ static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc); static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA); @@ -1240,7 +1283,7 @@ static void gsi_set_clear_dbell(struct usb_ep *ep, */ static bool gsi_check_ready_to_suspend(struct usb_ep *ep, bool f_suspend) { - u32 timeout = 500; + u32 timeout = 1500; u32 reg = 0; struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; @@ -1253,7 +1296,6 @@ static bool gsi_check_ready_to_suspend(struct usb_ep *ep, bool f_suspend) "Unable to suspend GSI ch. WR_CTRL_STATE != 0\n"); return false; } - usleep_range(20, 22); } /* Check for U3 only if we are not handling Function Suspend */ if (!f_suspend) { @@ -1935,7 +1977,6 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc) reg = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG); if (reg & PWR_EVNT_LPM_IN_L2_MASK) break; - usleep_range(20, 30); } if (!(reg & PWR_EVNT_LPM_IN_L2_MASK)) dev_err(mdwc->dev, "could not transition HS PHY to L2\n"); @@ -1998,10 +2039,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm)); - mutex_lock(&mdwc->suspend_resume_mutex); if (atomic_read(&dwc->in_lpm)) { dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__); - mutex_unlock(&mdwc->suspend_resume_mutex); return 0; } @@ -2018,7 +2057,6 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) __func__, evt->count / 4); dbg_print_reg("PENDING DEVICE EVENT", *(u32 *)(evt->buf + evt->lpos)); - mutex_unlock(&mdwc->suspend_resume_mutex); return -EBUSY; } } @@ -2038,7 +2076,6 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) dev_dbg(mdwc->dev, "%s: cable disconnected while not in idle otg state\n", __func__); - mutex_unlock(&mdwc->suspend_resume_mutex); return -EBUSY; } @@ -2052,15 +2089,12 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) pr_err("%s(): Trying to go in LPM with state:%d\n", __func__, dwc->gadget.state); pr_err("%s(): LPM is not performed.\n", __func__); - mutex_unlock(&mdwc->suspend_resume_mutex); return -EBUSY; } ret = dwc3_msm_prepare_suspend(mdwc); - if (ret) { - mutex_unlock(&mdwc->suspend_resume_mutex); + if (ret) return ret; - } /* Initialize variables here */ can_suspend_ssphy = !(mdwc->in_host_mode && @@ -2161,7 +2195,6 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) } dev_info(mdwc->dev, "DWC3 in low power mode\n"); - mutex_unlock(&mdwc->suspend_resume_mutex); return 0; } @@ -2173,10 +2206,8 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__); - mutex_lock(&mdwc->suspend_resume_mutex); if (!atomic_read(&dwc->in_lpm)) { dev_dbg(mdwc->dev, "%s: Already resumed\n", __func__); - mutex_unlock(&mdwc->suspend_resume_mutex); return 0; } @@ -2311,7 +2342,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC)); dbg_event(0xFF, "Ctl Res", atomic_read(&dwc->in_lpm)); - mutex_unlock(&mdwc->suspend_resume_mutex); return 0; } @@ -2479,6 +2509,284 @@ static irqreturn_t msm_dwc3_pwr_irq(int irq, void *data) return IRQ_HANDLED; } +#ifdef CONFIG_USB_DWC3_MSM_ID_POLL +static void dwc3_setsink_work(struct work_struct *w) +{ + struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, + setsink_work.work); + union power_supply_propval val = {0}; + int ret; + + if (!mdwc->otg_present && mdwc->setsink_cnt < SETSINK_RETRY_MAX) { + wake_lock_timeout(&mdwc->setsink_lock, + msecs_to_jiffies(WAKELOCK_RETRY_INTERVAL)); + mdwc->setsink_cnt++; + power_supply_get_property(mdwc->usb_psy, + POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val); + if (val.intval == POWER_SUPPLY_TYPEC_PR_SINK) { + pr_info("%s(): power role was changed to sink\n", + __func__); + return; + } + + val.intval = POWER_SUPPLY_TYPEC_PR_SINK; + ret = power_supply_set_property(mdwc->usb_psy, + POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val); + if (ret) { + dev_err(mdwc->dev, "set power supply fail\n"); + return; + } + pr_info("%s(): rerun set to sink\n", __func__); + schedule_delayed_work(&mdwc->setsink_work, + msecs_to_jiffies(SETSINK_RETRY_INTERVAL)); + } else { + if (mdwc->otg_present) + pr_info("%s(): cable is connected, so power role does not change\n", + __func__); + else + dev_err(mdwc->dev, + "retry count is over, power role has not changed.\n"); + } +} + +static void dwc3_id_pullup(struct dwc3_msm *mdwc, int pullup) +{ + if (pullup) { + dev_dbg(mdwc->dev, "%s: pull up ID pin\n", __func__); + if (mdwc->id_polling_pd_gpio) + gpio_set_value(mdwc->id_polling_pd_gpio, 1); + } else { + if (mdwc->id_polling_pd_gpio) + gpio_set_value(mdwc->id_polling_pd_gpio, 0); + dev_dbg(mdwc->dev, "%s: pull down ID pin\n", __func__); + } +} + +static ssize_t id_polling_up_interval_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + + if (!mdwc) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%u\n", mdwc->id_polling_up_interval); +} + +static ssize_t id_polling_up_interval_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + + if (!mdwc) + return -EINVAL; + + if (kstrtou32(buf, 0, &mdwc->id_polling_up_interval) < 0) { + pr_err("id_polling_up_interval cannot read value\n"); + return -EINVAL; + } + + if (mdwc->id_polling_start) { + /* restart id polling with new interval value. */ + cancel_delayed_work_sync(&mdwc->id_polling_work); + queue_delayed_work(mdwc->id_polling_q, &mdwc->id_polling_work, + msecs_to_jiffies(mdwc->id_polling_up_interval)); + } + + return size; +} + +static DEVICE_ATTR(id_polling_up_interval, S_IRUGO | S_IWUSR, + id_polling_up_interval_show, + id_polling_up_interval_store); + +static ssize_t id_polling_up_period_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + + if (!mdwc) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%u\n", mdwc->id_polling_up_period); +} + +static ssize_t id_polling_up_period_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct dwc3_msm *mdwc = dev_get_drvdata(dev); + + if (!mdwc) + return -EINVAL; + + if (kstrtou32(buf, 0, &mdwc->id_polling_up_period) < 0) { + pr_err("id_polling_up_period cannot read value\n"); + return -EINVAL; + } + + return size; +} + +static DEVICE_ATTR(id_polling_up_period, S_IRUGO | S_IWUSR, + id_polling_up_period_show, + id_polling_up_period_store); + +static void dwc3_id_poll_update(struct dwc3_msm *mdwc) +{ + if (!mdwc->otg_present && mdwc->lcd_blanked) { + mdwc->id_polling_start = false; + cancel_delayed_work(&mdwc->id_polling_work); + } else if (!mdwc->id_polling_start) { + mdwc->id_polling_start = true; + queue_delayed_work(mdwc->id_polling_q, &mdwc->id_polling_work, + 0); + } +} + +#ifdef CONFIG_FB +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct dwc3_msm *mdwc = container_of(self, struct dwc3_msm, fb_notif); + struct fb_event *evdata = data; + unsigned int blanked; + unsigned long flags; + + if (!mdwc->id_polling_use || !evdata || !evdata->data || + event != FB_EVENT_BLANK) + return 0; + + blanked = !(*(unsigned int *)(evdata->data) == FB_BLANK_UNBLANK); + + dev_info(mdwc->dev, "receive fb event blank=%u->%u, otg_present=%d\n", + mdwc->lcd_blanked, blanked, mdwc->otg_present); + + if (blanked == mdwc->lcd_blanked) + return 0; + + spin_lock_irqsave(&mdwc->id_polling_lock, flags); + mdwc->lcd_blanked = blanked; + dwc3_id_poll_update(mdwc); + spin_unlock_irqrestore(&mdwc->id_polling_lock, flags); + + return 0; +} +#endif /* CONFIG_FB */ + +static int dwc3_msm_set_type_power_role(struct dwc3_msm *mdwc, + int typec_power_role) +{ + union power_supply_propval pval = {0}; + int ret; + + if (!mdwc->usb_psy) { + mdwc->usb_psy = power_supply_get_by_name("usb"); + if (!mdwc->usb_psy) { + dev_warn(mdwc->dev, "Could not get usb power_supply\n"); + return -ENODEV; + } + } + pr_info("%s(): typec power role=%d\n", __func__, typec_power_role); + pval.intval = typec_power_role; + ret = power_supply_set_property(mdwc->usb_psy, + POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval); + if (ret) { + dev_err(mdwc->dev, + "power supply error when setting property\n"); + return ret; + } + + if (typec_power_role == POWER_SUPPLY_TYPEC_PR_SINK) { + mdwc->setsink_cnt = 0; + wake_lock_timeout(&mdwc->setsink_lock, + msecs_to_jiffies(WAKELOCK_RETRY_INTERVAL)); + schedule_delayed_work(&mdwc->setsink_work, + msecs_to_jiffies(SETSINK_RETRY_INTERVAL)); + } + return 0; +} + +static int dwc3_get_usb_detect_adc(struct dwc3_msm *mdwc) +{ + int rc = 0; + struct qpnp_vadc_result results; + + if (IS_ERR_OR_NULL(mdwc->usb_detect_adc)) { + mdwc->usb_detect_adc = qpnp_get_vadc(mdwc->dev, "usb_detect"); + if (IS_ERR(mdwc->usb_detect_adc)) + return PTR_ERR(mdwc->usb_detect_adc); + } + + rc = qpnp_vadc_read(mdwc->usb_detect_adc, 0x14, &results); + if (rc) + return 1; + else + return (800000 < results.physical); +} + +static void dwc3_id_polling_work(struct work_struct *w) +{ + struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, + id_polling_work.work); + enum dwc3_id_state id; + unsigned int delta; + unsigned long flags; + bool otg_present; + + if (!mdwc->id_polling_use) + return; + + spin_lock_irqsave(&mdwc->id_polling_lock, flags); + if (!mdwc->id_polling_start) { + spin_unlock_irqrestore(&mdwc->id_polling_lock, flags); + return; + } + queue_delayed_work(mdwc->id_polling_q, to_delayed_work(w), + msecs_to_jiffies(mdwc->id_polling_up_interval)); + spin_unlock_irqrestore(&mdwc->id_polling_lock, flags); + + pr_debug("id polling, interval=%u ms, period=%u us\n", + mdwc->id_polling_up_interval, + mdwc->id_polling_up_period); + + __pm_stay_awake(&mdwc->id_polling_wu); + dwc3_id_pullup(mdwc, 1); + + if (mdwc->id_polling_up_period) { + if (mdwc->id_polling_up_period < 10) { + udelay(mdwc->id_polling_up_period); + } else if (mdwc->id_polling_up_period < 20000) { + delta = mdwc->id_polling_up_period / 10; + usleep_range(mdwc->id_polling_up_period - delta, + mdwc->id_polling_up_period + delta); + } else if (mdwc->id_polling_up_period / 1000 < + mdwc->id_polling_up_interval) { + msleep(mdwc->id_polling_up_period / 1000); + } else { + pr_warn("pull up period is too long because it is longer than interval.\n"); + } + } + + id = dwc3_get_usb_detect_adc(mdwc) ? DWC3_ID_FLOAT : DWC3_ID_GROUND; + dwc3_id_pullup(mdwc, 0); + + spin_lock_irqsave(&mdwc->id_polling_lock, flags); + otg_present = mdwc->otg_present; + mdwc->otg_present = id == DWC3_ID_GROUND; + dwc3_id_poll_update(mdwc); + spin_unlock_irqrestore(&mdwc->id_polling_lock, flags); + + if (mdwc->otg_present != otg_present) { + dwc3_msm_set_type_power_role(mdwc, mdwc->otg_present ? + POWER_SUPPLY_TYPEC_PR_DUAL : + POWER_SUPPLY_TYPEC_PR_SINK); + __pm_wakeup_event(&mdwc->id_polling_wu, + USB_ID_POLLING_WAKE_TIMEOUT); + } + __pm_relax(&mdwc->id_polling_wu); +} +#endif /* CONFIG_USB_DWC3_MSM_ID_POLL */ + static int dwc3_cpu_notifier_cb(struct notifier_block *nfb, unsigned long action, void *hcpu) { @@ -2645,23 +2953,22 @@ done: return NOTIFY_DONE; } - -static void check_for_sdp_connection(struct work_struct *w) +static int dwc3_msm_vbus_drop_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) { - struct dwc3_msm *mdwc = - container_of(w, struct dwc3_msm, sdp_check.work); - struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); - - if (!mdwc->vbus_active) - return; + struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, vbus_drop_nb); + struct extcon_dev *edev = ptr; - /* floating D+/D- lines detected */ - if (dwc->gadget.state < USB_STATE_DEFAULT && - dwc3_gadget_get_link_state(dwc) != DWC3_LINK_STATE_CMPLY) { - mdwc->vbus_active = 0; - dbg_event(0xFF, "Q RW SPD CHK", mdwc->vbus_active); - queue_work(mdwc->dwc3_wq, &mdwc->resume_work); + if (!edev) { + dev_err(mdwc->dev, "%s: edev null\n", __func__); + goto done; } + + set_bit(A_VBUS_DROP_DET, &mdwc->inputs); + pr_info("%s: receive ocp notification\n", __func__); + schedule_delayed_work(&mdwc->sm_work, 0); +done: + return NOTIFY_DONE; } static int dwc3_msm_vbus_notifier(struct notifier_block *nb, @@ -2756,10 +3063,22 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc) dev_err(mdwc->dev, "failed to register notifier for USB-HOST\n"); goto err; } + + mdwc->extcon_vbus_drop = edev; + mdwc->vbus_drop_nb.notifier_call = dwc3_msm_vbus_drop_notifier; + ret = extcon_register_notifier(edev, EXTCON_VBUS_DROP, + &mdwc->vbus_drop_nb); + if (ret < 0) { + dev_err(mdwc->dev, "failed to register notifier for USB-DropT\n"); + goto err; + } } return 0; err: + if (mdwc->extcon_id) + extcon_unregister_notifier(mdwc->extcon_id, EXTCON_USB_HOST, + &mdwc->id_nb); if (mdwc->extcon_vbus) extcon_unregister_notifier(mdwc->extcon_vbus, EXTCON_USB, &mdwc->vbus_nb); @@ -2835,34 +3154,6 @@ static ssize_t speed_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(speed); static void msm_dwc3_perf_vote_work(struct work_struct *w); -static ssize_t xhci_link_compliance_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct dwc3_msm *mdwc = dev_get_drvdata(dev); - - if (mdwc->xhci_ss_compliance_enable) - return snprintf(buf, PAGE_SIZE, "y\n"); - else - return snprintf(buf, PAGE_SIZE, "n\n"); -} - -static ssize_t xhci_link_compliance_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct dwc3_msm *mdwc = dev_get_drvdata(dev); - bool value; - int ret; - - ret = strtobool(buf, &value); - if (!ret) { - mdwc->xhci_ss_compliance_enable = value; - return count; - } - - return ret; -} - -static DEVICE_ATTR_RW(xhci_link_compliance); static int dwc3_msm_probe(struct platform_device *pdev) { @@ -2900,7 +3191,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) INIT_WORK(&mdwc->vbus_draw_work, dwc3_msm_vbus_draw_work); INIT_DELAYED_WORK(&mdwc->sm_work, dwc3_otg_sm_work); INIT_DELAYED_WORK(&mdwc->perf_vote_work, msm_dwc3_perf_vote_work); - INIT_DELAYED_WORK(&mdwc->sdp_check, check_for_sdp_connection); mdwc->dwc3_wq = alloc_ordered_workqueue("dwc3_wq", 0); if (!mdwc->dwc3_wq) { @@ -2912,10 +3202,11 @@ static int dwc3_msm_probe(struct platform_device *pdev) ret = dwc3_msm_get_clk_gdsc(mdwc); if (ret) { dev_err(&pdev->dev, "error getting clock or gdsc.\n"); - goto err; + return ret; } mdwc->id_state = DWC3_ID_FLOAT; + mdwc->otg_present = true; set_bit(ID, &mdwc->inputs); mdwc->charging_disabled = of_property_read_bool(node, @@ -2959,9 +3250,8 @@ static int dwc3_msm_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, mdwc->ss_phy_irq, msm_dwc3_pwr_irq, msm_dwc3_pwr_irq_thread, - IRQF_TRIGGER_HIGH | IRQ_TYPE_LEVEL_HIGH - | IRQF_EARLY_RESUME | IRQF_ONESHOT, - "ss_phy_irq", mdwc); + IRQF_TRIGGER_RISING | IRQF_EARLY_RESUME + | IRQF_ONESHOT, "ss_phy_irq", mdwc); if (ret) { dev_err(&pdev->dev, "irqreq ss_phy_irq failed: %d\n", ret); @@ -2989,6 +3279,16 @@ static int dwc3_msm_probe(struct platform_device *pdev) } } +#ifdef CONFIG_USB_DWC3_MSM_ID_POLL + mdwc->id_polling_use = of_property_read_bool(node, "id_polling_use"); + if (mdwc->id_polling_use) { + dev_info(&pdev->dev, "id polling is enabled\n"); + mdwc->id_state = DWC3_ID_FLOAT; + } + + wake_lock_init(&mdwc->setsink_lock, WAKE_LOCK_SUSPEND, "typecsink_lock"); +#endif /* CONFIG_USB_DWC3_MSM_ID_POLL */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tcsr_base"); if (!res) { dev_dbg(&pdev->dev, "missing TCSR memory resource\n"); @@ -3191,7 +3491,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) POWER_SUPPLY_PROP_PRESENT, &pval); } - mutex_init(&mdwc->suspend_resume_mutex); /* Update initial VBUS/ID state from extcon */ if (mdwc->extcon_vbus && extcon_get_cable_state_(mdwc->extcon_vbus, EXTCON_USB)) @@ -3199,6 +3498,10 @@ static int dwc3_msm_probe(struct platform_device *pdev) else if (mdwc->extcon_id && extcon_get_cable_state_(mdwc->extcon_id, EXTCON_USB_HOST)) dwc3_msm_id_notifier(&mdwc->id_nb, true, mdwc->extcon_id); + else if (mdwc->extcon_vbus_drop && extcon_get_cable_state_( + mdwc->extcon_vbus_drop, EXTCON_VBUS_DROP)) + dwc3_msm_vbus_drop_notifier(&mdwc->vbus_drop_nb, true, + mdwc->extcon_vbus_drop); else if (!pval.intval) { /* USB cable is not connected */ schedule_delayed_work(&mdwc->sm_work, 0); @@ -3209,7 +3512,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) device_create_file(&pdev->dev, &dev_attr_mode); device_create_file(&pdev->dev, &dev_attr_speed); - device_create_file(&pdev->dev, &dev_attr_xhci_link_compliance); host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; if (host_mode || @@ -3219,24 +3521,70 @@ static int dwc3_msm_probe(struct platform_device *pdev) dwc3_ext_event_notify(mdwc); } +#ifdef CONFIG_USB_DWC3_MSM_ID_POLL + if (mdwc->id_polling_use) { + INIT_DELAYED_WORK(&mdwc->setsink_work, dwc3_setsink_work); + INIT_DELAYED_WORK(&mdwc->id_polling_work, dwc3_id_polling_work); + mdwc->id_polling_q = + create_singlethread_workqueue("id_polling_q"); + + mdwc->id_polling_up_interval = USB_ID_POLLING_UP_INTERVAL; + of_property_read_u32(node, "id_polling_up_interval", + &mdwc->id_polling_up_interval); + dev_dbg(&pdev->dev, "id_polling_up_interval=%dms\n", + mdwc->id_polling_up_interval); + device_create_file(&pdev->dev, + &dev_attr_id_polling_up_interval); + + mdwc->id_polling_up_period = USB_ID_POLLING_UP_PERIOD; + of_property_read_u32(node, "id_polling_up_period", + &mdwc->id_polling_up_period); + dev_dbg(&pdev->dev, "id_polling_up_period=%dus\n", + mdwc->id_polling_up_period); + device_create_file(&pdev->dev, &dev_attr_id_polling_up_period); + + mdwc->id_polling_pd_gpio = of_get_named_gpio(node, + "id_polling_pd_gpio", 0); + if (!gpio_is_valid(mdwc->id_polling_pd_gpio)) + dev_info(&pdev->dev, "id_polling_pd is missing\n"); + + wakeup_source_init(&mdwc->id_polling_wu, "id_polling"); + spin_lock_init(&mdwc->id_polling_lock); + +#ifdef CONFIG_FB + mdwc->fb_notif.notifier_call = fb_notifier_callback; + if (fb_register_client(&mdwc->fb_notif)) + dev_err(mdwc->dev, "failed to register fb_notifier\n"); +#endif /* CONFIG_FB */ + mdwc->id_polling_start = true; + queue_delayed_work(mdwc->id_polling_q, &mdwc->id_polling_work, + msecs_to_jiffies(mdwc->id_polling_up_interval)); + } +#endif /* CONFIG_USB_DWC3_MSM_ID_POLL */ + return 0; put_dwc3: + platform_device_put(mdwc->dwc3); if (mdwc->bus_perf_client) msm_bus_scale_unregister_client(mdwc->bus_perf_client); - of_platform_depopulate(&pdev->dev); err: - destroy_workqueue(mdwc->dwc3_wq); + wake_lock_destroy(&mdwc->setsink_lock); return ret; } +static int dwc3_msm_remove_children(struct device *dev, void *data) +{ + device_unregister(dev); + return 0; +} + static int dwc3_msm_remove(struct platform_device *pdev) { struct dwc3_msm *mdwc = platform_get_drvdata(pdev); int ret_pm; device_remove_file(&pdev->dev, &dev_attr_mode); - device_remove_file(&pdev->dev, &dev_attr_xhci_link_compliance); if (cpu_to_affin) unregister_cpu_notifier(&mdwc->dwc3_cpu_notifier); @@ -3262,11 +3610,28 @@ static int dwc3_msm_remove(struct platform_device *pdev) } cancel_delayed_work_sync(&mdwc->perf_vote_work); +#ifdef CONFIG_USB_DWC3_MSM_ID_POLL + cancel_delayed_work_sync(&mdwc->setsink_work); + wake_lock_destroy(&mdwc->setsink_lock); + if (mdwc->id_polling_use) { +#ifdef CONFIG_FB + fb_unregister_client(&mdwc->fb_notif); +#endif /* CONFIG_FB */ + wakeup_source_trash(&mdwc->id_polling_wu); + device_remove_file(&pdev->dev, + &dev_attr_id_polling_up_interval); + device_remove_file(&pdev->dev, &dev_attr_id_polling_up_period); + cancel_delayed_work_sync(&mdwc->id_polling_work); + destroy_workqueue(mdwc->id_polling_q); + } +#endif /* CONFIG_USB_DWC3_MSM_ID_POLL */ + cancel_delayed_work_sync(&mdwc->sm_work); if (mdwc->hs_phy) mdwc->hs_phy->flags &= ~PHY_HOST_MODE; - of_platform_depopulate(&pdev->dev); + platform_device_put(mdwc->dwc3); + device_for_each_child(&pdev->dev, NULL, dwc3_msm_remove_children); dbg_event(0xFF, "Remov put", 0); pm_runtime_disable(mdwc->dev); @@ -3449,16 +3814,13 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) dev_dbg(mdwc->dev, "%s: turn on host\n", __func__); mdwc->hs_phy->flags |= PHY_HOST_MODE; - if (dwc->maximum_speed == USB_SPEED_SUPER) { + if (dwc->maximum_speed == USB_SPEED_SUPER) mdwc->ss_phy->flags |= PHY_HOST_MODE; - usb_phy_notify_connect(mdwc->ss_phy, - USB_SPEED_SUPER); - } - usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); pm_runtime_get_sync(mdwc->dev); dbg_event(0xFF, "StrtHost gync", atomic_read(&mdwc->dev->power.usage_count)); + usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); if (!IS_ERR(mdwc->vbus_reg)) ret = regulator_enable(mdwc->vbus_reg); if (ret) { @@ -3502,25 +3864,6 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) return ret; } - /* - * If the Compliance Transition Capability(CTC) flag of - * HCCPARAMS2 register is set and xhci_link_compliance sysfs - * param has been enabled by the user for the SuperSpeed host - * controller, then write 10 (Link in Compliance Mode State) - * onto the Port Link State(PLS) field of the PORTSC register - * for 3.0 host controller which is at an offset of USB3_PORTSC - * + 0x10 from the DWC3 base address. Also, disable the runtime - * PM of 3.0 root hub (root hub of shared_hcd of xhci device) - */ - if (HCC_CTC(dwc3_msm_read_reg(mdwc->base, USB3_HCCPARAMS2)) - && mdwc->xhci_ss_compliance_enable - && dwc->maximum_speed == USB_SPEED_SUPER) { - dwc3_msm_write_reg(mdwc->base, USB3_PORTSC + 0x10, - 0x10340); - pm_runtime_disable(&hcd_to_xhci(platform_get_drvdata( - dwc->xhci))->shared_hcd->self.root_hub->dev); - } - /* * In some cases it is observed that USB PHY is not going into * suspend with host mode suspend functionality. Hence disable @@ -3566,13 +3909,8 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) dbg_event(0xFF, "StopHost gsync", atomic_read(&mdwc->dev->power.usage_count)); usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); - if (mdwc->ss_phy->flags & PHY_HOST_MODE) { - usb_phy_notify_disconnect(mdwc->ss_phy, - USB_SPEED_SUPER); - mdwc->ss_phy->flags &= ~PHY_HOST_MODE; - } - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; + mdwc->ss_phy->flags &= ~PHY_HOST_MODE; platform_device_del(dwc->xhci); usb_unregister_notify(&mdwc->host_nb); @@ -3679,46 +4017,34 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) return 0; } -int get_psy_type(struct dwc3_msm *mdwc) +static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA) { union power_supply_propval pval = {0}; + int ret; if (mdwc->charging_disabled) - return -EINVAL; + return 0; + + if (mdwc->max_power == mA) + return 0; if (!mdwc->usb_psy) { mdwc->usb_psy = power_supply_get_by_name("usb"); if (!mdwc->usb_psy) { - dev_err(mdwc->dev, "Could not get usb psy\n"); + dev_warn(mdwc->dev, "Could not get usb power_supply\n"); return -ENODEV; } } - power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_REAL_TYPE, - &pval); - - return pval.intval; -} - -static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA) -{ - union power_supply_propval pval = {0}; - int ret, psy_type; - - if (mdwc->max_power == mA) + power_supply_get_property(mdwc->usb_psy, + POWER_SUPPLY_PROP_REAL_TYPE, &pval); + if (pval.intval != POWER_SUPPLY_TYPE_USB) return 0; - psy_type = get_psy_type(mdwc); - if (psy_type == POWER_SUPPLY_TYPE_USB) { - dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA); - /* Set max current limit in uA */ - pval.intval = 1000 * mA; - } else if (psy_type == POWER_SUPPLY_TYPE_USB_FLOAT) { - pval.intval = -ETIMEDOUT; - } else { - return 0; - } + dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA); + /* Set max current limit in uA */ + pval.intval = 1000 * mA; ret = power_supply_set_property(mdwc->usb_psy, POWER_SUPPLY_PROP_SDP_CURRENT_MAX, &pval); if (ret) { @@ -3730,7 +4056,6 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA) return 0; } - /** * dwc3_otg_sm_work - workqueue function. * @@ -3789,10 +4114,6 @@ static void dwc3_otg_sm_work(struct work_struct *w) work = 1; } else if (test_bit(B_SESS_VLD, &mdwc->inputs)) { dev_dbg(mdwc->dev, "b_sess_vld\n"); - if (get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_FLOAT) - queue_delayed_work(mdwc->dwc3_wq, - &mdwc->sdp_check, - msecs_to_jiffies(SDP_CONNETION_CHECK_TIME)); /* * Increment pm usage count upon cable connect. Count * is decremented in OTG_STATE_B_PERIPHERAL state on @@ -3806,6 +4127,7 @@ static void dwc3_otg_sm_work(struct work_struct *w) work = 1; break; } else { + mdwc->send_vbus_drop_ue = false; dwc3_msm_gadget_vbus_draw(mdwc, 0); dev_dbg(mdwc->dev, "Cable disconnected\n"); } @@ -3816,7 +4138,6 @@ static void dwc3_otg_sm_work(struct work_struct *w) !test_bit(ID, &mdwc->inputs)) { dev_dbg(mdwc->dev, "!id || !bsv\n"); mdwc->otg_state = OTG_STATE_B_IDLE; - cancel_delayed_work_sync(&mdwc->sdp_check); dwc3_otg_start_peripheral(mdwc, 0); /* * Decrement pm usage count upon cable disconnect @@ -3849,7 +4170,6 @@ static void dwc3_otg_sm_work(struct work_struct *w) if (!test_bit(B_SESS_VLD, &mdwc->inputs)) { dev_dbg(mdwc->dev, "BSUSP: !bsv\n"); mdwc->otg_state = OTG_STATE_B_IDLE; - cancel_delayed_work_sync(&mdwc->sdp_check); dwc3_otg_start_peripheral(mdwc, 0); } else if (!test_bit(B_SUSPEND, &mdwc->inputs)) { dev_dbg(mdwc->dev, "BSUSP !susp\n"); @@ -3870,9 +4190,22 @@ static void dwc3_otg_sm_work(struct work_struct *w) /* Switch to A-Device*/ if (test_bit(ID, &mdwc->inputs)) { dev_dbg(mdwc->dev, "id\n"); + clear_bit(A_VBUS_DROP_DET, &mdwc->inputs); mdwc->otg_state = OTG_STATE_B_IDLE; mdwc->vbus_retry_count = 0; work = 1; +#ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION + host_send_uevent(USB_HOST_EXT_EVENT_NONE); +#endif + } else if (test_bit(A_VBUS_DROP_DET, &mdwc->inputs)) { + dev_dbg(mdwc->dev, "vbus_drop_det\n"); + /* staying on here until exit from A-Device */ +#ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION + if (!mdwc->send_vbus_drop_ue) { + mdwc->send_vbus_drop_ue = true; + host_send_uevent(USB_HOST_EXT_EVENT_VBUS_DROP); + } +#endif } else { mdwc->otg_state = OTG_STATE_A_HOST; ret = dwc3_otg_start_host(mdwc, 1); @@ -3903,6 +4236,20 @@ static void dwc3_otg_sm_work(struct work_struct *w) mdwc->vbus_retry_count = 0; mdwc->hc_died = false; work = 1; +#ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION + host_send_uevent(USB_HOST_EXT_EVENT_NONE); +#endif + } else if (test_bit(A_VBUS_DROP_DET, &mdwc->inputs)) { + dev_dbg(mdwc->dev, "vbus_drop_det\n"); + dwc3_otg_start_host(mdwc, 0); + mdwc->otg_state = OTG_STATE_A_IDLE; + mdwc->vbus_retry_count = 0; +#ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION + if (!mdwc->send_vbus_drop_ue) { + mdwc->send_vbus_drop_ue = true; + host_send_uevent(USB_HOST_EXT_EVENT_VBUS_DROP); + } +#endif } else { dev_dbg(mdwc->dev, "still in a_host state. Resuming root hub.\n"); dbg_event(0xFF, "XHCIResume", 0); diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index 81db2fa08cad6beea9b1b5590e2dbf4b223b58ee..5c0adb9c6fb27baa778615f17705ac6ab7896079 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -224,7 +224,7 @@ static int st_dwc3_probe(struct platform_device *pdev) dwc3_data->syscfg_reg_off = res->start; - dev_vdbg(&pdev->dev, "glue-logic addr 0x%pK, syscfg-reg offset 0x%x\n", + dev_vdbg(&pdev->dev, "glue-logic addr 0x%p, syscfg-reg offset 0x%x\n", dwc3_data->glue_base, dwc3_data->syscfg_reg_off); dwc3_data->rstc_pwrdn = devm_reset_control_get(dev, "powerdown"); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index c244d908fa4f9d84256d1ebda09884d0c591f4eb..c2a6fdbfcfee885bde9fd7bfc0d430ebcbc9d8a9 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -439,7 +439,6 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, dwc->ep0_usb_req.request.length = sizeof(*response_pkt); dwc->ep0_usb_req.request.buf = dwc->setup_buf; dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; - dwc->ep0_usb_req.request.dma = DMA_ERROR_CODE; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } @@ -730,7 +729,6 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; dwc->ep0_usb_req.request.buf = dwc->setup_buf; dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; - dwc->ep0_usb_req.request.dma = DMA_ERROR_CODE; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 94709587f2382183734d1e1d091a8783d7878c37..658fcca485d86773130ebe76e8f83f39121cac87 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1340,32 +1340,6 @@ static bool dwc3_gadget_is_suspended(struct dwc3 *dwc) return false; } -static void __dwc3_gadget_ep_zlp_complete(struct usb_ep *ep, - struct usb_request *request) -{ - dwc3_gadget_ep_free_request(ep, request); -} - -static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep) -{ - struct dwc3_request *req; - struct usb_request *request; - struct usb_ep *ep = &dep->endpoint; - - dwc3_trace(trace_dwc3_gadget, "queueing ZLP\n"); - request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC); - if (!request) - return -ENOMEM; - - request->length = 0; - request->buf = dwc->zlp_buf; - request->complete = __dwc3_gadget_ep_zlp_complete; - - req = to_dwc3_request(request); - - return __dwc3_gadget_ep_queue(dep, req); -} - static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags) { @@ -1413,16 +1387,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, ret = __dwc3_gadget_ep_queue(dep, req); - /* - * Okay, here's the thing, if gadget driver has requested for a ZLP by - * setting request->zero, instead of doing magic, we will just queue an - * extra usb_request ourselves so that it gets handled the same way as - * any other request. - */ - if (ret == 0 && request->zero && request->length && - (request->length % ep->maxpacket == 0)) - ret = __dwc3_gadget_ep_queue_zlp(dwc, dep); - out: spin_unlock_irqrestore(&dwc->lock, flags); @@ -3590,12 +3554,6 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err3; } - dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL); - if (!dwc->zlp_buf) { - ret = -ENOMEM; - goto err4; - } - dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; @@ -3637,12 +3595,12 @@ int dwc3_gadget_init(struct dwc3 *dwc) ret = dwc3_gadget_init_endpoints(dwc); if (ret) - goto err5; + goto err4; ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); - goto err5; + goto err4; } if (!dwc->is_drd) { @@ -3654,9 +3612,6 @@ int dwc3_gadget_init(struct dwc3 *dwc) return 0; -err5: - kfree(dwc->zlp_buf); - err4: dwc3_gadget_free_endpoints(dwc); dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, @@ -3694,7 +3649,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc->ep0_bounce, dwc->ep0_bounce_addr); kfree(dwc->setup_buf); - kfree(dwc->zlp_buf); dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 0787e36742aa8b79fab0c4e81713216af5a6b7ef..042722e4f200763a44fe905f7b53fc408de42b0c 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -573,6 +573,13 @@ config USB_CONFIGFS_F_CCID USB CCID function driver creats transport layer between the userspace CCID component and the Windows Host. +config USB_ANDROID_PRODUCTION + boolean "Production capable Android gadget" + depends on USB_CONFIGFS + default n + help + Provides an Android gadget where iSerialNumber is set to 0. + source "drivers/usb/gadget/legacy/Kconfig" endchoice diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 22ba45f40f0b316f4d0cd82d4c7ee74e54e44e9d..529851bae7557f7ad89fff61c8f7af0455027cf7 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -8,6 +8,11 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* #define VERBOSE_DEBUG */ @@ -35,8 +40,7 @@ (speed == USB_SPEED_SUPER ?\ SSUSB_GADGET_VBUS_DRAW : CONFIG_USB_GADGET_VBUS_DRAW) -/* disable LPM by default */ -static bool disable_l1_for_hs = true; +static bool disable_l1_for_hs; module_param(disable_l1_for_hs, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(disable_l1_for_hs, "Disable support for L1 LPM for HS devices"); @@ -1691,9 +1695,9 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min(w_length, (u16) value); break; case USB_DT_BOS: - if ((gadget_is_superspeed(gadget) && - (gadget->speed >= USB_SPEED_SUPER)) - || !disable_l1_for_hs) { + if (gadget_is_superspeed(gadget) && + ((gadget->speed >= USB_SPEED_SUPER) + || !disable_l1_for_hs)) { value = bos_desc(cdev); value = min(w_length, (u16) value); } @@ -2088,7 +2092,7 @@ static ssize_t suspended_show(struct device *dev, struct device_attribute *attr, struct usb_gadget *gadget = dev_to_usb_gadget(dev); struct usb_composite_dev *cdev = get_gadget_data(gadget); - return snprintf(buf, PAGE_SIZE, "%d\n", cdev->suspended); + return sprintf(buf, "%d\n", cdev->suspended); } static DEVICE_ATTR_RO(suspended); diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index a2c14bb5efa4e55f97f4019a5a4c194afd860f40..d44d0469cf3b97cad529b0b4bf3de7d2695df29c 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -1337,7 +1342,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget, gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id; gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id; +#ifdef CONFIG_USB_ANDROID_PRODUCTION + /* Set id to 0 to comply with Sony production tools */ + gi->cdev.desc.iSerialNumber = 0; +#else gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id; +#endif } if (gi->use_os_desc) { diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c index 7950f25136a59b26210d24961614a880baec7144..4d9c631d8355c630c8d799f2ce14a5082667dc8f 100644 --- a/drivers/usb/gadget/function/f_accessory.c +++ b/drivers/usb/gadget/function/f_accessory.c @@ -14,6 +14,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* #define DEBUG */ /* #define VERBOSE_DEBUG */ @@ -346,7 +351,6 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) struct acc_dev *dev = ep->driver_data; char *string_dest = NULL; int length = req->actual; - unsigned long flags; if (req->status != 0) { pr_err("acc_complete_set_string, err %d\n", req->status); @@ -372,26 +376,22 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) case ACCESSORY_STRING_SERIAL: string_dest = dev->serial; break; - default: - pr_err("unknown accessory string index %d\n", - dev->string_index); - return; - } - - if (!length) { - pr_debug("zero length for accessory string index %d\n", - dev->string_index); - return; } + if ((string_dest) && (length != 0)) { + unsigned long flags; - if (length >= ACC_STRING_SIZE) - length = ACC_STRING_SIZE - 1; + if (length >= ACC_STRING_SIZE) + length = ACC_STRING_SIZE - 1; - spin_lock_irqsave(&dev->lock, flags); - memcpy(string_dest, req->buf, length); - /* ensure zero termination */ - string_dest[length] = 0; - spin_unlock_irqrestore(&dev->lock, flags); + spin_lock_irqsave(&dev->lock, flags); + memcpy(string_dest, req->buf, length); + /* ensure zero termination */ + string_dest[length] = 0; + spin_unlock_irqrestore(&dev->lock, flags); + } else { + pr_err("unknown accessory string index %d\n", + dev->string_index); + } } static void acc_complete_set_hid_report_desc(struct usb_ep *ep, @@ -699,6 +699,7 @@ static ssize_t acc_write(struct file *fp, const char __user *buf, ssize_t r = count; unsigned xfer; int ret; + int sendZLP = 0; pr_debug("acc_write(%zu)\n", count); @@ -707,7 +708,14 @@ static ssize_t acc_write(struct file *fp, const char __user *buf, return -ENODEV; } - while (count > 0) { + if ((count & (dev->ep_in->maxpacket - 1)) == 0) + sendZLP = 1; + + while ((count > 0) || (sendZLP == 1)) { + /* exit after sending ZLP */ + if (count == 0) + sendZLP = 0; + if (!dev->online) { pr_debug("acc_write dev->error\n"); r = -EIO; @@ -732,8 +740,9 @@ static ssize_t acc_write(struct file *fp, const char __user *buf, /* * If the data length is a multple of the * maxpacket size then send a zero length packet(ZLP). + * + * req->zero = ((xfer % dev->ep_in->maxpacket) == 0); */ - req->zero = ((xfer % dev->ep_in->maxpacket) == 0); } if (copy_from_user(req->buf, buf, xfer)) { r = -EFAULT; diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c index ec73b67096c5673b881f1550f2da9f4d77ea75f8..40fe10fb0e528383f2ea7c0f8eec9babd0a03660 100644 --- a/drivers/usb/gadget/function/f_audio_source.c +++ b/drivers/usb/gadget/function/f_audio_source.c @@ -13,6 +13,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -246,6 +251,7 @@ struct audio_source_config { struct audio_dev { struct usb_function func; + u8 ctrl_id; struct snd_card *card; struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -599,6 +605,16 @@ static int audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) return 0; } +static int audio_get_alt(struct usb_function *f, unsigned intf) +{ + struct audio_dev *audio = func_to_audio(f); + if (intf == audio->ctrl_id) { + return 0; + } + + return audio->in_ep->enabled ? 1 : 0; +} + static void audio_disable(struct usb_function *f) { struct audio_dev *audio = func_to_audio(f); @@ -665,6 +681,8 @@ audio_bind(struct usb_configuration *c, struct usb_function *f) status = usb_interface_id(c, f); if (status < 0) goto fail; + audio->ctrl_id = status; + ac_interface_desc.bInterfaceNumber = status; /* AUDIO_AC_INTERFACE */ @@ -862,6 +880,7 @@ static struct audio_dev _audio_dev = { .bind = audio_bind, .unbind = audio_unbind, .set_alt = audio_set_alt, + .get_alt = audio_get_alt, .setup = audio_setup, .disable = audio_disable, .free_func = audio_free_func, diff --git a/drivers/usb/gadget/function/f_ccid.c b/drivers/usb/gadget/function/f_ccid.c index 1a281833eadded7ed6e8743bb116169ad4f50fcd..28ac8d0010d8f23f31e18043d09bdcf3cbb06ece 100644 --- a/drivers/usb/gadget/function/f_ccid.c +++ b/drivers/usb/gadget/function/f_ccid.c @@ -26,7 +26,7 @@ #include "f_ccid.h" #define BULK_IN_BUFFER_SIZE sizeof(struct ccid_bulk_in_header) -#define BULK_OUT_BUFFER_SIZE 1024 +#define BULK_OUT_BUFFER_SIZE sizeof(struct ccid_bulk_out_header) #define CTRL_BUF_SIZE 4 #define FUNCTION_NAME "ccid" #define MAX_INST_NAME_LEN 40 @@ -629,14 +629,14 @@ static ssize_t ccid_bulk_read(struct file *fp, char __user *buf, struct f_ccid *ccid_dev = fp->private_data; struct ccid_bulk_dev *bulk_dev = &ccid_dev->bulk_dev; struct usb_request *req; - int r = count, xfer, len; + int r = count, xfer; int ret; unsigned long flags; pr_debug("ccid_bulk_read(%zu)\n", count); if (count > BULK_OUT_BUFFER_SIZE) { - pr_err("%s: max_buffer_size:%d given_pkt_size:%zu\n", + pr_err("%s: max_buffer_size:%zu given_pkt_size:%zu\n", __func__, BULK_OUT_BUFFER_SIZE, count); return -ENOMEM; } @@ -647,7 +647,6 @@ static ssize_t ccid_bulk_read(struct file *fp, char __user *buf, goto done; } - len = ALIGN(count, ccid_dev->out->maxpacket); requeue_req: spin_lock_irqsave(&ccid_dev->lock, flags); if (!atomic_read(&ccid_dev->online)) { @@ -656,7 +655,7 @@ requeue_req: } /* queue a request */ req = bulk_dev->rx_req; - req->length = len; + req->length = count; bulk_dev->rx_done = 0; spin_unlock_irqrestore(&ccid_dev->lock, flags); ret = usb_ep_queue(ccid_dev->out, req, GFP_KERNEL); @@ -689,9 +688,6 @@ requeue_req: spin_unlock_irqrestore(&ccid_dev->lock, flags); goto requeue_req; } - if (req->actual > count) - pr_err("%s More data received(%d) than required(%zu)\n", - __func__, req->actual, count); xfer = (req->actual < count) ? req->actual : count; atomic_set(&bulk_dev->rx_req_busy, 1); spin_unlock_irqrestore(&ccid_dev->lock, flags); @@ -879,8 +875,7 @@ static ssize_t ccid_ctrl_read(struct file *fp, char __user *buf, count = CTRL_BUF_SIZE; ret = wait_event_interruptible(ctrl_dev->tx_wait_q, - ctrl_dev->tx_ctrl_done || - !atomic_read(&ccid_dev->online)); + ctrl_dev->tx_ctrl_done); if (ret < 0) return ret; ctrl_dev->tx_ctrl_done = 0; diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 19fe6c8cb25aa0fbee9a5c167f88bb1b8fb04c03..ea286c648178db9e622316c0af61fc327c14eb73 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "f_gsi.h" #include "rndis.h" @@ -1579,12 +1584,6 @@ static void gsi_rndis_command_complete(struct usb_ep *ep, struct f_gsi *rndis = req->context; int status; - if (req->status != 0) { - log_event_err("RNDIS command completion error %d\n", - req->status); - return; - } - status = rndis_msg_parser(rndis->params, (u8 *) req->buf); if (status < 0) log_event_err("RNDIS command error %d, %d/%d", @@ -2442,6 +2441,30 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) switch (gsi->prot_id) { case IPA_USB_RNDIS: + /* "Wireless" RNDIS6; auto-detected by Windows */ + pr_debug("%s: linux_support=%d\n", __func__, + gsi->linux_support); + if (gsi->linux_support) { + pr_info("%s: RNDIS5\n", __func__); + rndis_gsi_control_intf.bInterfaceClass = + USB_CLASS_WIRELESS_CONTROLLER; + rndis_gsi_control_intf.bInterfaceSubClass = 0x01; + rndis_gsi_control_intf.bInterfaceProtocol = 0x03; + rndis_gsi_iad_descriptor.bFunctionClass = + USB_CLASS_WIRELESS_CONTROLLER; + rndis_gsi_iad_descriptor.bFunctionSubClass = 0x01; + rndis_gsi_iad_descriptor.bFunctionProtocol = 0x03; + } else { + pr_info("%s: RNDIS6\n", __func__); + rndis_gsi_control_intf.bInterfaceClass = USB_CLASS_MISC; + rndis_gsi_control_intf.bInterfaceSubClass = 0x04; + rndis_gsi_control_intf.bInterfaceProtocol = 0x01; + rndis_gsi_iad_descriptor.bFunctionClass = + USB_CLASS_MISC; + rndis_gsi_iad_descriptor.bFunctionSubClass = 0x04; + rndis_gsi_iad_descriptor.bFunctionProtocol = 0x01; + } + info.string_defs = rndis_gsi_string_defs; info.ctrl_desc = &rndis_gsi_control_intf; info.ctrl_str_idx = 0; @@ -2819,6 +2842,8 @@ static struct f_gsi *gsi_function_init(enum ipa_usb_teth_prot prot_id) gsi->d_port.ipa_usb_wq = ipa_usb_wq; + gsi->linux_support = false; + ret = gsi_function_ctrl_port_init(gsi); if (ret) { kfree(gsi); @@ -2984,10 +3009,56 @@ static ssize_t gsi_info_show(struct config_item *item, char *page) return ret; } +static ssize_t gsi_linux_support_show(struct config_item *item, char *page) +{ + struct f_gsi *gsi = to_gsi_opts(item)->gsi; + int ret; + + switch (gsi->prot_id) { + case IPA_USB_RNDIS: + /* "Y\n\0" 3characters */ + ret = snprintf(page, 3, "%c\n", gsi->linux_support ? 'Y' : 'N'); + break; + default: + ret = EBADR; + break; + } + + return ret; +} + +static ssize_t gsi_linux_support_store(struct config_item *item, + const char *page, size_t len) +{ + struct f_gsi *gsi = to_gsi_opts(item)->gsi; + bool val; + int ret = 0; + + switch (gsi->prot_id) { + case IPA_USB_RNDIS: + ret = strtobool(page, &val); + if (ret) + break; + gsi->linux_support = val; + pr_info("%s: set linux_support=%d.\n", __func__, + gsi->linux_support); + break; + default: + ret = -EBADR; + break; + } + + if (ret) + len = ret; + return len; +} + +CONFIGFS_ATTR(gsi_, linux_support); CONFIGFS_ATTR_RO(gsi_, info); static struct configfs_attribute *gsi_attrs[] = { &gsi_attr_info, + &gsi_attr_linux_support, NULL, }; diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 262a60e8a4506b9aac73135d7686659c6b8eaf87..0ea5c62a426a18b113066947ffdb0fb4814ef0f5 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _F_GSI_H #define _F_GSI_H @@ -243,6 +248,7 @@ struct f_gsi { struct gsi_data_port d_port; struct gsi_ctrl_port c_port; + bool linux_support; }; static inline struct f_gsi *func_to_gsi(struct usb_function *f) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 9b7274821d0b3195e766c12d66024f06053fcf3a..f3469c41fff55d00afce72f20eb0aa0cfca2b917 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -36,6 +36,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * The Mass Storage Function acts as a USB Mass Storage device, @@ -222,6 +227,7 @@ #include "configfs.h" +#define USB_SOMC_MAC_SUPPORT /*------------------------------------------------------------------------*/ @@ -249,6 +255,8 @@ static struct usb_gadget_strings *fsg_strings_array[] = { NULL, }; +#define TOC_FORMAT2_SIZE (11 * 3 + 4) + /*-------------------------------------------------------------------------*/ struct fsg_dev; @@ -1239,6 +1247,8 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) int msf = common->cmnd[1] & 0x02; int start_track = common->cmnd[6]; u8 *buf = (u8 *)bh->buf; + u8 format; + int offset; if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ start_track > 1) { @@ -1246,18 +1256,55 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) return -EINVAL; } - memset(buf, 0, 20); - buf[1] = (20-2); /* TOC data length */ - buf[2] = 1; /* First track number */ - buf[3] = 1; /* Last track number */ - buf[5] = 0x16; /* Data track, copying allowed */ - buf[6] = 0x01; /* Only track is number 1 */ - store_cdrom_address(&buf[8], msf, 0); - - buf[13] = 0x16; /* Lead-out track is data */ - buf[14] = 0xAA; /* Lead-out track number */ - store_cdrom_address(&buf[16], msf, curlun->num_sectors); - return 20; + format = common->cmnd[2] & 0x07; + /* SFF-8020i: When Format in Byte 2 is zero, then Byte 9 is used. */ + if (format == 0) + format = (common->cmnd[9] >> 6) & 0x03; + + if (format == 0) { + memset(buf, 0, 20); + buf[1] = (20-2); /* TOC data length */ + buf[2] = 1; /* First track number */ + buf[3] = 1; /* Last track number */ + buf[5] = 0x16; /* Data track, copying allowed */ + buf[6] = 0x01; /* Only track is number 1 */ + store_cdrom_address(&buf[8], msf, 0); + + buf[13] = 0x16; /* Lead-out track is data */ + buf[14] = 0xAA; /* Lead-out track number */ + store_cdrom_address(&buf[16], msf, curlun->num_sectors); + return 20; + } else if (format == 0x02) { + memset(buf, 0, TOC_FORMAT2_SIZE); + buf[1] = (TOC_FORMAT2_SIZE-2); /* TOC data length */ + buf[2] = 1; /* First Session Number */ + buf[3] = 1; /* Last Session Number */ + offset = 4; + + buf[offset] = 1; /* Session Number */ + buf[offset + 1] = 0x16; /* Data track, copying allowed */ + buf[offset + 2] = 0; /* TNO */ + buf[offset + 3] = 0xA0; /* Point */ + buf[offset + 8] = 1; /* First track number */ + buf[offset + 9] = 0; /* Disc Type */ + offset += 11; + + buf[offset] = 1; /* Session Number */ + buf[offset + 1] = 0x16; /* Data track, copying allowed */ + buf[offset + 2] = 0; /* TNO */ + buf[offset + 3] = 0xA1; /* Point */ + buf[offset + 8] = 1; /* Last track number */ + offset += 11; + + buf[offset] = 1; /* Session Number */ + buf[offset + 1] = 0x16; /* Data track, copying allowed */ + buf[offset + 2] = 0; /* TNO */ + buf[offset + 3] = 0xA2; /* Point */ + store_cdrom_address(&buf[offset + 7], msf, curlun->num_sectors); + return TOC_FORMAT2_SIZE; + } + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; } static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) @@ -1396,6 +1443,7 @@ static int do_start_stop(struct fsg_common *common) return 0; } +#if !defined(USB_SOMC_MAC_SUPPORT) static int do_prevent_allow(struct fsg_common *common) { struct fsg_lun *curlun = common->curlun; @@ -1419,6 +1467,7 @@ static int do_prevent_allow(struct fsg_common *common) curlun->prevent_medium_removal = prevent; return 0; } +#endif static int do_read_format_capacities(struct fsg_common *common, struct fsg_buffhd *bh) @@ -1923,6 +1972,7 @@ static int do_scsi_command(struct fsg_common *common) reply = do_mode_sense(common, bh); break; +#if !defined(USB_SOMC_MAC_SUPPORT) case ALLOW_MEDIUM_REMOVAL: common->data_size_from_cmnd = 0; reply = check_command(common, 6, DATA_DIR_NONE, @@ -1931,6 +1981,7 @@ static int do_scsi_command(struct fsg_common *common) if (reply == 0) reply = do_prevent_allow(common); break; +#endif case READ_6: i = common->cmnd[4]; @@ -1992,7 +2043,7 @@ static int do_scsi_command(struct fsg_common *common) common->data_size_from_cmnd = get_unaligned_be16(&common->cmnd[7]); reply = check_command(common, 10, DATA_DIR_TO_HOST, - (7<<6) | (1<<1), 1, + (0x0f<<6) | (1<<1), 1, "READ TOC"); if (reply == 0) reply = do_read_toc(common, bh); @@ -3075,7 +3126,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) fsg->common->can_stall); if (ret) return ret; - fsg_common_set_inquiry_string(fsg->common, NULL, NULL); + fsg_common_set_inquiry_string(fsg->common, "SONY", "CD-ROM"); } if (!common->thread_task) { @@ -3323,6 +3374,7 @@ static struct config_group *fsg_lun_make(struct config_group *group, memset(&config, 0, sizeof(config)); config.removable = true; + config.cdrom = true; ret = fsg_common_create_lun(fsg_opts->common, &config, num, name, (const char **)&group->cg_item.ci_name); @@ -3515,6 +3567,7 @@ static struct usb_function_instance *fsg_alloc_inst(void) memset(&config, 0, sizeof(config)); config.removable = true; + config.cdrom = true; rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0", (const char **)&opts->func_inst.group.cg_item.ci_name); if (rc) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 79f554f1fb23ba6e76699eed78d7fd22590b8c56..d77a6d627560e866be6e654c2e8a9ef8f7e4846f 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -18,6 +18,11 @@ * * Licensed under the GPL-2 or later. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -944,6 +949,8 @@ fail_f_midi: kfree(midi_function); usb_free_descriptors(f->hs_descriptors); kfree(midi_ss_function); + if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors) + usb_free_descriptors(f->ss_descriptors); fail: f_midi_unregister_card(midi); fail_register: diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index d8cc5fd39e854095d3d7d98b376cb8170b88df46..26d91978cd4d45cf03f0fc8bcbb62b03c9e49a90 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -14,6 +14,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* #define DEBUG */ /* #define VERBOSE_DEBUG */ @@ -58,12 +63,17 @@ #define STATE_BUSY 2 /* processing userspace calls */ #define STATE_CANCELED 3 /* transaction canceled by host */ #define STATE_ERROR 4 /* error from completion routine */ +#define STATE_RESET 5 /* reset the device */ /* number of tx and rx requests to allocate */ #define MTP_TX_REQ_MAX 8 #define RX_REQ_MAX 2 #define INTR_REQ_MAX 5 +/* vendor code */ +#define MSOS_VENDOR_CODE 0x08 +#define MSOS_GOOGLE_VENDOR_CODE 0x01 + /* ID for Microsoft MTP OS String */ #define MTP_OS_STRING_ID 0xEE @@ -139,6 +149,7 @@ struct mtp_dev { unsigned dbg_write_index; bool is_ptp; struct mutex read_mutex; + bool isMSOSDesc; }; static struct usb_interface_descriptor mtp_interface_desc = { @@ -201,7 +212,7 @@ static struct usb_endpoint_descriptor mtp_highspeed_in_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), + .wMaxPacketSize = cpu_to_le16(512), }; static struct usb_endpoint_descriptor mtp_highspeed_out_desc = { @@ -209,7 +220,7 @@ static struct usb_endpoint_descriptor mtp_highspeed_out_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), + .wMaxPacketSize = cpu_to_le16(512), }; static struct usb_endpoint_descriptor mtp_fullspeed_in_desc = { @@ -231,7 +242,7 @@ static struct usb_endpoint_descriptor mtp_intr_desc = { .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(INTR_BUFFER_SIZE), + .wMaxPacketSize = cpu_to_le16(INTR_BUFFER_SIZE), .bInterval = 6, }; @@ -322,7 +333,7 @@ static u8 mtp_os_string[] = { /* Signature field: "MSFT100" */ 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, /* vendor code */ - 1, + MSOS_GOOGLE_VENDOR_CODE, /* padding */ 0 }; @@ -347,27 +358,13 @@ struct mtp_ext_config_desc_function { /* MTP Extended Configuration Descriptor */ struct ext_mtp_desc { - struct mtp_ext_config_desc_header header; + struct mtp_ext_config_desc_header header; struct mtp_ext_config_desc_function function; }; -struct ext_mtp_desc mtp_ext_config_desc = { - .header = { - .dwLength = __constant_cpu_to_le32(sizeof(mtp_ext_config_desc)), - .bcdVersion = __constant_cpu_to_le16(0x0100), - .wIndex = __constant_cpu_to_le16(4), - .bCount = 1, - }, - .function = { - .bFirstInterfaceNumber = 0, - .bInterfaceCount = 1, - .compatibleID = { 'M', 'T', 'P' }, - }, -}; - struct ext_mtp_desc ptp_ext_config_desc = { .header = { - .dwLength = cpu_to_le32(sizeof(mtp_ext_config_desc)), + .dwLength = cpu_to_le32(sizeof(ptp_ext_config_desc)), .bcdVersion = cpu_to_le16(0x0100), .wIndex = cpu_to_le16(4), .bCount = cpu_to_le16(1), @@ -497,7 +494,7 @@ static void mtp_complete_out(struct usb_ep *ep, struct usb_request *req) struct mtp_dev *dev = _mtp_dev; dev->rx_done = 1; - if (req->status != 0 && dev->state != STATE_OFFLINE) + if (req->status != 0 && dev->state != STATE_BUSY) dev->state = STATE_ERROR; wake_up(&dev->read_wq); @@ -639,6 +636,12 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, dev->state = STATE_READY; spin_unlock_irq(&dev->lock); return -ECANCELED; + } else if (dev->state == STATE_RESET) { + /* report a reset state to userspace */ + dev->state = STATE_READY; + spin_unlock_irq(&dev->lock); + DBG(cdev, "mtp_read DEVICE RESET. State: %d.\n", dev->state); + return -ECONNRESET; } dev->state = STATE_BUSY; spin_unlock_irq(&dev->lock); @@ -675,7 +678,7 @@ requeue_req: spin_unlock_irq(&dev->lock); goto done; } - if (ret < 0) { + if (ret < 0 || !dev->rx_done) { r = ret; usb_ep_dequeue(dev->ep_out, req); goto done; @@ -699,6 +702,8 @@ done: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) r = -ECANCELED; + else if (dev->state == STATE_RESET) + r = -ECONNRESET; else if (dev->state != STATE_OFFLINE) dev->state = STATE_READY; spin_unlock_irq(&dev->lock); @@ -1016,6 +1021,21 @@ static void receive_file_work(struct work_struct *data) r = read_req->status; break; } + if (dev->state == STATE_OFFLINE) { + r = -ENODEV; + if (!dev->rx_done) + usb_ep_dequeue(dev->ep_out, read_req); + break; + } + if (dev->state == STATE_RESET) { + DBG(cdev, "%s: DEVICE RESET\n", __func__); + r = -ECONNRESET; + if (!dev->rx_done) { + DBG(cdev, "dequeue in DEVICE RESET\n"); + usb_ep_dequeue(dev->ep_out, read_req); + } + break; + } mutex_lock(&dev->read_mutex); if (dev->state == STATE_OFFLINE) { @@ -1105,6 +1125,14 @@ static long mtp_send_receive_ioctl(struct file *fp, unsigned code, ret = -ECANCELED; goto out; } + if (dev->state == STATE_RESET) { + /* report reset to userspace */ + DBG(dev->cdev, "report reset to user space\n"); + dev->state = STATE_READY; + spin_unlock_irq(&dev->lock); + ret = -ECONNRESET; + goto out; + } if (dev->state == STATE_OFFLINE) { spin_unlock_irq(&dev->lock); ret = -ENODEV; @@ -1156,6 +1184,8 @@ fail: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) ret = -ECANCELED; + else if (dev->state == STATE_RESET) + ret = -ECONNRESET; else if (dev->state != STATE_OFFLINE) dev->state = STATE_READY; spin_unlock_irq(&dev->lock); @@ -1344,26 +1374,59 @@ static int mtp_ctrlrequest(struct usb_composite_dev *cdev, DBG(cdev, "vendor request: %d index: %d value: %d length: %d\n", ctrl->bRequest, w_index, w_value, w_length); - if (ctrl->bRequest == 1 - && (ctrl->bRequestType & USB_DIR_IN) - && (w_index == 4 || w_index == 5)) { - if (!dev->is_ptp) { - value = (w_length < - sizeof(mtp_ext_config_desc) ? - w_length : - sizeof(mtp_ext_config_desc)); - memcpy(cdev->req->buf, &mtp_ext_config_desc, - value); - } else { - value = (w_length < - sizeof(ptp_ext_config_desc) ? - w_length : - sizeof(ptp_ext_config_desc)); - memcpy(cdev->req->buf, &ptp_ext_config_desc, - value); + if (((ctrl->bRequest == MSOS_GOOGLE_VENDOR_CODE) || + (ctrl->bRequest == MSOS_VENDOR_CODE)) && + (ctrl->bRequestType & USB_DIR_IN) && (w_index == 4)) { + + int total = 0; + int func_num = 0; + int interface_num = 0; + struct mtp_ext_config_desc_header *head; + struct mtp_ext_config_desc_function *func; + struct usb_configuration *cfg; + struct usb_function *f; + + head = (struct mtp_ext_config_desc_header *) + cdev->req->buf; + func = (struct mtp_ext_config_desc_function *) + (head + 1); + + /* zero clear */ + memset(cdev->req->buf, 0x00, USB_COMP_EP0_BUFSIZ); + + list_for_each_entry(cfg, &cdev->configs, list) { + + list_for_each_entry(f, &cfg->functions, list) { + if (!f) + break; + + interface_num++; + func->bFirstInterfaceNumber = func_num; + func->bInterfaceCount = 1; + if (!strncmp(f->name, "mtp", 3)) { + memcpy(func->compatibleID, + "MTP", 3); + VDBG(cdev, + "MTP interface found. Interface_num: %d.\n", + interface_num); + } + func++; + func_num++; + } } + + total = sizeof(*head) + (sizeof(*func) * func_num); + + /* header section */ + head->dwLength = total; + head->bcdVersion = cpu_to_le16(0x0100); + head->wIndex = cpu_to_le16(4); + head->bCount = func_num; + value = min_t(u16, w_length, total); + dev->isMSOSDesc = true; } - } else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { + } + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { DBG(cdev, "class request: %d index: %d value: %d length: %d\n", ctrl->bRequest, w_index, w_value, w_length); @@ -1379,6 +1442,23 @@ static int mtp_ctrlrequest(struct usb_composite_dev *cdev, } spin_unlock_irqrestore(&dev->lock, flags); + /* We need to queue a request to read the remaining + * bytes, but we don't actually need to look at + * the contents. + */ + value = w_length; + } else if (ctrl->bRequest == MTP_REQ_RESET && w_index == 0 + && w_value == 0) { + DBG(cdev, "MTP_REQ_RESET\n"); + + spin_lock_irqsave(&dev->lock, flags); + /* Flushing the buffers as mentioned in MTP spec */ + usb_ep_fifo_flush(dev->ep_out); + dev->state = STATE_RESET; + wake_up(&dev->read_wq); + wake_up(&dev->write_wq); + spin_unlock_irqrestore(&dev->lock, flags); + /* We need to queue a request to read the remaining * bytes, but we don't actually need to look at * the contents. @@ -1399,6 +1479,9 @@ static int mtp_ctrlrequest(struct usb_composite_dev *cdev, if (dev->state == STATE_CANCELED) status->wCode = __cpu_to_le16(MTP_RESPONSE_DEVICE_BUSY); + else if (dev->state == STATE_RESET) + status->wCode = + __cpu_to_le16(MTP_RESPONSE_OK); else status->wCode = __cpu_to_le16(MTP_RESPONSE_OK); @@ -1519,6 +1602,7 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) mutex_unlock(&dev->read_mutex); dev->state = STATE_OFFLINE; dev->is_ptp = false; + dev->isMSOSDesc = false; kfree(f->os_desc_table); f->os_desc_n = 0; fi_mtp->func_inst.f = NULL; @@ -1784,8 +1868,24 @@ static struct configfs_item_operations mtp_item_ops = { .release = mtp_attr_release, }; +static ssize_t mtp_isMSOSDesc_show(struct config_item *item, + char *page) +{ + struct mtp_dev *dev = to_mtp_instance(item)->dev; + + return snprintf(page, 3, "%s\n", dev->isMSOSDesc ? "Y" : "N"); +} + +CONFIGFS_ATTR_RO(mtp_, isMSOSDesc); + +static struct configfs_attribute *mtp_config_attrs[] = { + &mtp_attr_isMSOSDesc, + NULL, +}; + static struct config_item_type mtp_func_type = { .ct_item_ops = &mtp_item_ops, + .ct_attrs = mtp_config_attrs, .ct_owner = THIS_MODULE, }; diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c index a28bcd084dc363ffa3717c233371f72c818407cb..434af820e827bf3cb97f1f2c58aebace130c8646 100644 --- a/drivers/usb/gadget/function/f_qc_rndis.c +++ b/drivers/usb/gadget/function/f_qc_rndis.c @@ -545,12 +545,6 @@ static void rndis_qc_command_complete(struct usb_ep *ep, rndis_init_msg_type *buf; u32 ul_max_xfer_size, dl_max_xfer_size; - if (req->status != 0) { - pr_err("%s: RNDIS command completion error %d\n", - __func__, req->status); - return; - } - spin_lock(&rndis_lock); rndis = _rndis_qc; if (!rndis || !rndis->notify || !rndis->notify->driver_data) { diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 8536f10a2e355c8542dcbd1f3b7404ba0bd6c0fa..777acb48987583046ce4d69c5050cd5e600f2a01 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -183,28 +183,15 @@ static struct usb_qdss_opts *to_fi_usb_qdss_opts(struct usb_function_instance *f } /*----------------------------------------------------------------------*/ -static void qdss_write_complete(struct usb_ep *ep, +static void qdss_ctrl_write_complete(struct usb_ep *ep, struct usb_request *req) { struct f_qdss *qdss = ep->driver_data; struct qdss_request *d_req = req->context; - struct usb_ep *in; - struct list_head *list_pool; - enum qdss_state state; unsigned long flags; pr_debug("qdss_ctrl_write_complete\n"); - if (qdss->debug_inface_enabled) { - in = qdss->port.ctrl_in; - list_pool = &qdss->ctrl_write_pool; - state = USB_QDSS_CTRL_WRITE_DONE; - } else { - in = qdss->port.data; - list_pool = &qdss->data_write_pool; - state = USB_QDSS_DATA_WRITE_DONE; - } - if (!req->status) { /* send zlp */ if ((req->length >= ep->maxpacket) && @@ -212,13 +199,13 @@ static void qdss_write_complete(struct usb_ep *ep, req->length = 0; d_req->actual = req->actual; d_req->status = req->status; - if (!usb_ep_queue(in, req, GFP_ATOMIC)) + if (!usb_ep_queue(qdss->port.ctrl_in, req, GFP_ATOMIC)) return; } } spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, list_pool); + list_add_tail(&req->list, &qdss->ctrl_write_pool); if (req->length != 0) { d_req->actual = req->actual; d_req->status = req->status; @@ -226,7 +213,8 @@ static void qdss_write_complete(struct usb_ep *ep, spin_unlock_irqrestore(&qdss->lock, flags); if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, state, d_req, NULL); + qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_WRITE_DONE, d_req, + NULL); } static void qdss_ctrl_read_complete(struct usb_ep *ep, @@ -264,12 +252,6 @@ void usb_qdss_free_req(struct usb_qdss_ch *ch) return; } - list_for_each_safe(act, tmp, &qdss->data_write_pool) { - req = list_entry(act, struct usb_request, list); - list_del(&req->list); - usb_ep_free_request(qdss->port.data, req); - } - list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) { req = list_entry(act, struct usb_request, list); list_del(&req->list); @@ -289,41 +271,23 @@ int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf, { struct f_qdss *qdss = ch->priv_usb; struct usb_request *req; - struct usb_ep *in; - struct list_head *list_pool; int i; pr_debug("usb_qdss_alloc_req\n"); - if (!qdss) { - pr_err("usb_qdss_alloc_req: channel %s closed\n", ch->name); - return -ENODEV; - } - - if ((qdss->debug_inface_enabled && - (no_write_buf <= 0 || no_read_buf <= 0)) || - (!qdss->debug_inface_enabled && - (no_write_buf <= 0 || no_read_buf))) { + if (no_write_buf <= 0 || no_read_buf <= 0 || !qdss) { pr_err("usb_qdss_alloc_req: missing params\n"); return -ENODEV; } - if (qdss->debug_inface_enabled) { - in = qdss->port.ctrl_in; - list_pool = &qdss->ctrl_write_pool; - } else { - in = qdss->port.data; - list_pool = &qdss->data_write_pool; - } - for (i = 0; i < no_write_buf; i++) { - req = usb_ep_alloc_request(in, GFP_ATOMIC); + req = usb_ep_alloc_request(qdss->port.ctrl_in, GFP_ATOMIC); if (!req) { pr_err("usb_qdss_alloc_req: ctrl_in allocation err\n"); goto fail; } - req->complete = qdss_write_complete; - list_add_tail(&req->list, list_pool); + req->complete = qdss_ctrl_write_complete; + list_add_tail(&req->list, &qdss->ctrl_write_pool); } for (i = 0; i < no_read_buf; i++) { @@ -515,20 +479,21 @@ static void usb_qdss_disconnect_work(struct work_struct *work) qdss = container_of(work, struct f_qdss, disconnect_w); pr_debug("usb_qdss_disconnect_work\n"); - - /* Notify qdss to cancel all active transfers */ - if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, - USB_QDSS_DISCONNECT, - NULL, - NULL); - - /* Uninitialized init data i.e. ep specific operation */ - if (qdss->ch.app_conn && !strcmp(qdss->ch.name, USB_QDSS_CH_MSM)) { + /* + * Uninitialized init data i.e. ep specific operation. + * Notify qdss to cancel all active transfers. + */ + if (qdss->ch.app_conn) { status = uninit_data(qdss->port.data); if (status) pr_err("%s: uninit_data error\n", __func__); + if (qdss->ch.notify) + qdss->ch.notify(qdss->ch.priv, + USB_QDSS_DISCONNECT, + NULL, + NULL); + status = set_qdss_data_connection(qdss, 0); if (status) pr_err("qdss_disconnect error"); @@ -585,16 +550,15 @@ static void usb_qdss_connect_work(struct work_struct *work) } pr_debug("usb_qdss_connect_work\n"); - - if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) - goto notify; - status = set_qdss_data_connection(qdss, 1); if (status) { pr_err("set_qdss_data_connection error(%d)", status); return; } + if (qdss->ch.notify) + qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, + NULL, &qdss->ch); spin_lock_irqsave(&qdss->lock, flags); req = qdss->endless_req; spin_unlock_irqrestore(&qdss->lock, flags); @@ -602,15 +566,8 @@ static void usb_qdss_connect_work(struct work_struct *work) return; status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC); - if (status) { + if (status) pr_err("%s: usb_ep_queue error (%d)\n", __func__, status); - return; - } - -notify: - if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, - NULL, &qdss->ch); } static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt) @@ -749,7 +706,6 @@ static struct f_qdss *alloc_usb_qdss(char *channel_name) spin_lock_init(&qdss->lock); INIT_LIST_HEAD(&qdss->ctrl_read_pool); INIT_LIST_HEAD(&qdss->ctrl_write_pool); - INIT_LIST_HEAD(&qdss->data_write_pool); INIT_WORK(&qdss->connect_w, usb_qdss_connect_work); INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work); @@ -845,50 +801,6 @@ int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) } EXPORT_SYMBOL(usb_qdss_ctrl_write); -int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) -{ - struct f_qdss *qdss = ch->priv_usb; - unsigned long flags; - struct usb_request *req = NULL; - - pr_debug("usb_qdss_ctrl_write\n"); - - if (!qdss) - return -ENODEV; - - spin_lock_irqsave(&qdss->lock, flags); - - if (qdss->usb_connected == 0) { - spin_unlock_irqrestore(&qdss->lock, flags); - return -EIO; - } - - if (list_empty(&qdss->data_write_pool)) { - pr_err("error: usb_qdss_data_write list is empty\n"); - spin_unlock_irqrestore(&qdss->lock, flags); - return -EAGAIN; - } - - req = list_first_entry(&qdss->data_write_pool, struct usb_request, - list); - list_del(&req->list); - spin_unlock_irqrestore(&qdss->lock, flags); - - req->buf = d_req->buf; - req->length = d_req->length; - req->context = d_req; - if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) { - spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, &qdss->data_write_pool); - spin_unlock_irqrestore(&qdss->lock, flags); - pr_err("qdss usb_ep_queue failed\n"); - return -EIO; - } - - return 0; -} -EXPORT_SYMBOL(usb_qdss_write); - struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv, void (*notify)(void *, unsigned, struct qdss_request *, struct usb_qdss_ch *)) @@ -947,9 +859,7 @@ void usb_qdss_close(struct usb_qdss_ch *ch) pr_debug("usb_qdss_close\n"); spin_lock_irqsave(&qdss_lock, flags); - ch->priv_usb = NULL; - if (!qdss || !qdss->usb_connected || - !strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) { + if (!qdss || !qdss->usb_connected) { ch->app_conn = 0; spin_unlock_irqrestore(&qdss_lock, flags); return; diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h index fb7c01c0f9391a69300275aaaa7d5775b6db82d9..cad0f4cc06f94889e252b259f01e076f233b1729 100644 --- a/drivers/usb/gadget/function/f_qdss.h +++ b/drivers/usb/gadget/function/f_qdss.h @@ -53,10 +53,6 @@ struct f_qdss { struct usb_qdss_ch ch; struct list_head ctrl_read_pool; struct list_head ctrl_write_pool; - - /* for mdm channel SW path */ - struct list_head data_write_pool; - struct work_struct connect_w; struct work_struct disconnect_w; spinlock_t lock; diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 0917bc5000234fe2380bc23fe74794ae53617ba2..13888821109d369a5a69753fde24dfb2742ab19b 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -463,12 +463,6 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) int status; rndis_init_msg_type *buf; - if (req->status != 0) { - pr_err("%s: RNDIS command completion error:%d\n", - __func__, req->status); - return; - } - /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ // spin_lock(&dev->lock); status = rndis_msg_parser(rndis->params, (u8 *) req->buf); diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index d62683017cf3c1c052f78eb243799e1ca46ca8d5..53bbb99a3d9293583d2266819963c925988b11d1 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -10,6 +10,11 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * This file requires the following identifiers used in USB strings to @@ -301,7 +306,6 @@ void store_cdrom_address(u8 *dest, int msf, u32 addr) { if (msf) { /* Convert to Minutes-Seconds-Frames */ - addr >>= 2; /* Convert to 2048-byte frames */ addr += 2*75; /* Lead-in occupies 2 seconds */ dest[3] = addr % 75; /* Frames */ addr /= 75; diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 1ffed7b74d3fe9e1e75a4d5af50edfa5b21711d5..9123f1635843688126d886bf4518ab25327c96a6 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1073,9 +1073,6 @@ int gether_set_dev_addr(struct net_device *net, const char *dev_addr) struct eth_dev *dev; u8 new_addr[ETH_ALEN]; - if (!net) - return -ENODEV; - dev = netdev_priv(net); if (get_ether_addr(dev_addr, new_addr)) return -EINVAL; @@ -1088,9 +1085,6 @@ int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len) { struct eth_dev *dev; - if (!net) - return -ENODEV; - dev = netdev_priv(net); return get_ether_addr_str(dev->dev_mac, dev_addr, len); } @@ -1101,9 +1095,6 @@ int gether_set_host_addr(struct net_device *net, const char *host_addr) struct eth_dev *dev; u8 new_addr[ETH_ALEN]; - if (!net) - return -ENODEV; - dev = netdev_priv(net); if (get_ether_addr(host_addr, new_addr)) return -EINVAL; @@ -1116,9 +1107,6 @@ int gether_get_host_addr(struct net_device *net, char *host_addr, int len) { struct eth_dev *dev; - if (!net) - return -ENODEV; - dev = netdev_priv(net); return get_ether_addr_str(dev->host_mac, host_addr, len); } @@ -1151,9 +1139,6 @@ void gether_set_qmult(struct net_device *net, unsigned qmult) { struct eth_dev *dev; - if (!net) - return; - dev = netdev_priv(net); dev->qmult = qmult; } @@ -1163,9 +1148,6 @@ unsigned gether_get_qmult(struct net_device *net) { struct eth_dev *dev; - if (!net) - return -ENODEV; - dev = netdev_priv(net); return dev->qmult; } @@ -1173,9 +1155,6 @@ EXPORT_SYMBOL_GPL(gether_get_qmult); int gether_get_ifname(struct net_device *net, char *name, int len) { - if (!net) - return -ENODEV; - rtnl_lock(); strlcpy(name, netdev_name(net), len); rtnl_unlock(); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3bb08870148f467de4869c133fa6adfef4602116..c6300d3c619786b30507193aeb242e2b66159fb9 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -785,3 +785,10 @@ config USB_HCD_TEST_MODE This option is of interest only to developers who need to validate their USB hardware designs. It is not needed for normal use. If unsure, say N. + +config USB_HOST_EXTRA_NOTIFICATION + bool "USB host extra notification" + depends on USB + default n + help + Provides the functions to notify extra USB host related events. diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index e7558abc994d76be29a347ed6904bca36d3765de..24e95233466a7dcc29b05a1b125837d0fef68898 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -76,3 +76,4 @@ obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o +obj-$(CONFIG_USB_HOST_EXTRA_NOTIFICATION) += host_ext_event.o diff --git a/drivers/usb/host/host_ext_event.c b/drivers/usb/host/host_ext_event.c new file mode 100644 index 0000000000000000000000000000000000000000..df78d03edda813507901d519b7bf104730d65870 --- /dev/null +++ b/drivers/usb/host/host_ext_event.c @@ -0,0 +1,171 @@ + /* drivers/usb/host/host_ext_event.c + * + * USB host event handling function + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2013 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NAME_SIZE 32 +#define MAX_MODULE_NAME_SIZE 32 +#define MAX_EVENT_STRING_SIZE 35 + +struct host_ext_event_drv { + struct class *class; + struct device *dev; + char name[MAX_NAME_SIZE + 1]; + int event; +}; + +static DEFINE_SEMAPHORE(sem); + +static struct host_ext_event_drv *host_ext_event; + +static const char *event_string(enum usb_host_ext_event event) +{ + switch (event) { + case USB_HOST_EXT_EVENT_NONE: + return "USB_HOST_NONE"; + case USB_HOST_EXT_EVENT_VBUS_DROP: + return "USB_HOST_VBUS_DROP"; + case USB_HOST_EXT_EVENT_INSUFFICIENT_POWER: + return "USB_HOST_INSUFFICIENT_POWER"; + default: + return "UNDEFINED"; + } +} + +int host_send_uevent(enum usb_host_ext_event event) +{ + struct host_ext_event_drv *dev = host_ext_event; + + char udev_event[MAX_EVENT_STRING_SIZE]; + char module[MAX_MODULE_NAME_SIZE]; + char *envp[] = {module, udev_event, NULL}; + int ret; + + if (dev == NULL) + return -ENODEV; + + ret = down_interruptible(&sem); + if (ret < 0) + return ret; + + pr_info("%s: sending %s event\n", dev->name, event_string(event)); + + snprintf(udev_event, MAX_EVENT_STRING_SIZE, "EVENT=%s", + event_string(event)); + snprintf(module, MAX_MODULE_NAME_SIZE, "MODULE=%s", dev->name); + ret = kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, envp); + + dev->event = event; + + up(&sem); + + if (ret < 0) + pr_info("uevent sending failed with ret = %d\n", ret); + + return ret; +} + +static int usb_host_ext_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + int ret; + + struct host_ext_event_drv *udev = host_ext_event; + + if (udev == NULL) + return -ENODEV; + + ret = add_uevent_var(env, "%d", udev->event); + if (ret) { + dev_err(dev, "failed to add usb host ext uevent\n"); + return ret; + } + + return 0; +} + +static int __init host_ext_event_driver_register(void) +{ + struct host_ext_event_drv *dev; + int ret; + + if (host_ext_event) + return -EBUSY; + + dev = kzalloc(sizeof(struct host_ext_event_drv), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + host_ext_event = dev; + + dev->class = class_create(THIS_MODULE, "usb_host_ext_event"); + if (IS_ERR(dev->class)) { + pr_info("%s :failed to create class", __func__); + ret = PTR_ERR(dev->class); + goto class_create_fail; + } + + dev->class->dev_uevent = usb_host_ext_uevent; + + dev->event = USB_HOST_EXT_EVENT_NONE; + + strlcpy(dev->name, "usb_host_ext_event", MAX_NAME_SIZE); + + dev->dev = device_create(dev->class, NULL, MKDEV(0, 0), NULL, + dev->name); + if (IS_ERR(dev->dev)) { + pr_info("%s :failed to create device", __func__); + ret = PTR_ERR(dev->dev); + goto device_create_fail; + } + + pr_info("usb_host_ext_event has been registered!"); + + return 0; + +device_create_fail: + class_destroy(dev->class); +class_create_fail: + kfree(dev); + host_ext_event = NULL; + return ret; +} + +static void __exit host_ext_event_driver_unregister(void) +{ + struct host_ext_event_drv *dev = host_ext_event; + + down(&sem); + + device_destroy(dev->class, MKDEV(0, 0)); + class_destroy(dev->class); + kfree(dev); + host_ext_event = NULL; + + up(&sem); +} + +module_init(host_ext_event_driver_register); +module_exit(host_ext_event_driver_unregister); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Extra event notifier of USB host"); diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index c894479c192200a52de0230f0dfda16a738c77d5..b090aa17d99febe55ed9e30edea8d7b9e596aa93 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -27,6 +32,7 @@ #include #include #include +#include #include "usbpd.h" /* To start USB stack for USB3.1 complaince testing */ @@ -182,7 +188,7 @@ static void *usbpd_ipc_log; #define PS_HARD_RESET_TIME 25 #define PS_SOURCE_ON 400 #define PS_SOURCE_OFF 750 -#define FIRST_SOURCE_CAP_TIME 200 +#define SWAP_SOURCE_START_TIME 20 #define VDM_BUSY_TIME 50 #define VCONN_ON_TIME 100 @@ -201,6 +207,10 @@ static void *usbpd_ipc_log; #define PD_MSG_HDR(type, dr, pr, id, cnt, rev) \ (((type) & 0xF) | ((dr) << 5) | (rev << 6) | \ ((pr) << 8) | ((id) << 9) | ((cnt) << 12)) +#define USB_VBUS_WAIT_VOLT 900 /* mV */ +#define USB_VBUS_WAIT_ITVL 5 /* mS */ +#define USB_VBUS_WAIT_TMOUT 200 /* mS */ + #define PD_MSG_HDR_COUNT(hdr) (((hdr) >> 12) & 7) #define PD_MSG_HDR_TYPE(hdr) ((hdr) & 0xF) #define PD_MSG_HDR_ID(hdr) (((hdr) >> 9) & 7) @@ -280,6 +290,12 @@ static void *usbpd_ipc_log; #define ID_HDR_PRODUCT_AMA 5 #define ID_HDR_VID 0x05c6 /* qcom */ #define PROD_VDO_PID 0x0a00 /* TBD */ +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#undef ID_HDR_VID +#undef PROD_VDO_PID +#define ID_HDR_VID 0x0FCE /* Sony Mobile Communications */ +#define PROD_VDO_PID 0x01F3 +#endif static bool check_vsafe0v = true; module_param(check_vsafe0v, bool, S_IRUSR | S_IWUSR); @@ -287,7 +303,7 @@ module_param(check_vsafe0v, bool, S_IRUSR | S_IWUSR); static int min_sink_current = 900; module_param(min_sink_current, int, S_IRUSR | S_IWUSR); -static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */ +static const u32 default_src_caps[] = { 0x3601905A }; /* VSafe5V @ 0.9A */ static const u32 default_snk_caps[] = { 0x2601912C }; /* VSafe5V @ 3A */ struct vdm_tx { @@ -321,6 +337,9 @@ struct usbpd { u32 received_pdos[PD_MAX_DATA_OBJ]; u16 src_cap_id; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + u32 org_received_pdos[7]; +#endif u8 selected_pdo; u8 requested_pdo; u32 rdo; /* can be either source or sink */ @@ -386,12 +405,28 @@ static const unsigned int usbpd_extcon_cable[] = { EXTCON_USB_HOST, EXTCON_USB_CC, EXTCON_USB_SPEED, + EXTCON_VBUS_DROP, EXTCON_NONE, }; /* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */ static const u32 usbpd_extcon_exclusive[] = {0x3, 0}; +/** + * usbpd_ocp_notification - ocp notification callback from regulator. + * @ctxt: Pointer to the dwc3_msm context + * + * NOTE: This can be called in interrupt context. + */ +static void usbpd_ocp_notification(void *ctxt) +{ + struct usbpd *pd = (struct usbpd *)ctxt; + + extcon_set_cable_state_(pd->extcon, EXTCON_VBUS_DROP, 1); + extcon_set_cable_state_(pd->extcon, EXTCON_VBUS_DROP, 0); + pr_info("%s: receive ocp notification\n", __func__); +} + enum plug_orientation usbpd_get_plug_orientation(struct usbpd *pd) { int ret; @@ -481,15 +516,15 @@ static inline void pd_reset_protocol(struct usbpd *pd) pd->send_dr_swap = false; } -static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data, - size_t num_data, enum pd_sop_type sop) +static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data, + size_t num_data, enum pd_msg_type type) { int ret; u16 hdr; - hdr = PD_MSG_HDR(msg_type, pd->current_dr, pd->current_pr, + hdr = PD_MSG_HDR(hdr_type, pd->current_dr, pd->current_pr, pd->tx_msgid, num_data, pd->spec_rev); - ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), sop, 15); + ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), type, 15); /* TODO figure out timeout. based on tReceive=1.1ms x nRetryCount? */ if (ret < 0) @@ -555,11 +590,37 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua) return 0; } +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define ACCEPTABLE_SRC_VOLTAGE_9V 9000 +#endif static int pd_eval_src_caps(struct usbpd *pd) { int obj_cnt; union power_supply_propval val; u32 first_pdo = pd->received_pdos[0]; +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + u32 *pdo = pd->received_pdos; + u32 *org_pdo = pd->org_received_pdos; + int i; + + for (i = 0; i < ARRAY_SIZE(pd->received_pdos); i++) + org_pdo[i] = pdo[i]; + + for (i = 1; i < ARRAY_SIZE(pd->received_pdos); i++) { + if (PD_SRC_PDO_TYPE(pdo[i]) == PD_SRC_PDO_TYPE_FIXED && + PD_SRC_PDO_FIXED_VOLTAGE(pdo[i]) * 50 <= + ACCEPTABLE_SRC_VOLTAGE_9V) + /* This PDO is acceptable */ + ; + else + break; + } + + usbpd_dbg(&pd->dev, "Clear PDOs from %d to %d\n", + i + 1, (int)ARRAY_SIZE(pd->received_pdos)); + for (; i < ARRAY_SIZE(pd->received_pdos); i++) + pdo[i] = 0; +#endif if (PD_SRC_PDO_TYPE(first_pdo) != PD_SRC_PDO_TYPE_FIXED) { usbpd_err(&pd->dev, "First src_cap invalid! %08x\n", first_pdo); @@ -612,12 +673,12 @@ static void kick_sm(struct usbpd *pd, int ms) queue_work(pd->wq, &pd->sm_work); } -static void phy_sig_received(struct usbpd *pd, enum pd_sig_type sig) +static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) { union power_supply_propval val = {1}; - if (sig != HARD_RESET_SIG) { - usbpd_err(&pd->dev, "invalid signal (%d) received\n", sig); + if (type != HARD_RESET_SIG) { + usbpd_err(&pd->dev, "invalid signal (%d) received\n", type); return; } @@ -632,16 +693,16 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type sig) kick_sm(pd, 0); } -static void phy_msg_received(struct usbpd *pd, enum pd_sop_type sop, +static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, u8 *buf, size_t len) { struct rx_msg *rx_msg; unsigned long flags; u16 header; - if (sop != SOP_MSG) { + if (type != SOP_MSG) { usbpd_err(&pd->dev, "invalid msg type (%d) received; only SOP supported\n", - sop); + type); return; } @@ -697,9 +758,41 @@ static void phy_msg_received(struct usbpd *pd, enum pd_sop_type sop, kick_sm(pd, 0); } +static void phy_wait_vbus_settled_down(struct usbpd *pd, int mv, + int itvl, int tmout) +{ + int rc; + int cnt = 0; + int usbin = mv; + + do { + union power_supply_propval pval; + + msleep(itvl); + rc = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); + if (IS_ERR_VALUE(rc)) + goto waitremain; + usbin = pval.intval / 1000; + cnt++; + } while (usbin >= mv && tmout > (cnt * itvl)); +waitremain: + if (usbin >= mv && tmout > (cnt * itvl)) + msleep(tmout - (cnt * itvl)); +} + + static void phy_shutdown(struct usbpd *pd) { usbpd_dbg(&pd->dev, "shutdown"); + + if (regulator_is_enabled(pd->vbus)) { + usbpd_info(&pd->dev, "turn off VBUS"); + regulator_disable(pd->vbus); + phy_wait_vbus_settled_down(pd, + USB_VBUS_WAIT_VOLT, USB_VBUS_WAIT_ITVL, + USB_VBUS_WAIT_TMOUT); + } } static enum hrtimer_restart pd_timeout(struct hrtimer *timer) @@ -790,27 +883,17 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->pd_phy_opened = true; } + pd->current_state = PE_SRC_SEND_CAPABILITIES; if (pd->in_pr_swap) { + kick_sm(pd, SWAP_SOURCE_START_TIME); pd->in_pr_swap = false; val.intval = 0; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val); + break; } - /* - * A sink might remove its terminations (during some Type-C - * compliance tests or a sink attempting to do Try.SRC) - * at this point just after we enabled VBUS. Sending PD - * messages now would delay detecting the detach beyond the - * required timing. Instead, delay sending out the first - * source capabilities to allow for the other side to - * completely settle CC debounce and allow HW to detect detach - * sooner in the meantime. PD spec allows up to - * tFirstSourceCap (250ms). - */ - pd->current_state = PE_SRC_SEND_CAPABILITIES; - kick_sm(pd, FIRST_SOURCE_CAP_TIME); - break; + /* fall-through */ case PE_SRC_SEND_CAPABILITIES: kick_sm(pd, 0); @@ -920,7 +1003,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) if (pd->psy_type == POWER_SUPPLY_TYPE_USB || pd->psy_type == POWER_SUPPLY_TYPE_USB_CDP || - pd->psy_type == POWER_SUPPLY_TYPE_USB_FLOAT || usb_compliance_mode) start_usb_peripheral(pd); } @@ -1451,7 +1533,6 @@ static void dr_swap(struct usbpd *pd) } pd_phy_update_roles(pd->current_dr, pd->current_pr); - dual_role_instance_changed(pd->dual_role); } @@ -1595,6 +1676,10 @@ static void usbpd_sm(struct work_struct *w) pd->requested_current = 0; pd->selected_pdo = pd->requested_pdo = 0; memset(&pd->received_pdos, 0, sizeof(pd->received_pdos)); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + memset(&pd->org_received_pdos, 0, + sizeof(pd->org_received_pdos)); +#endif rx_msg_cleanup(pd); power_supply_set_property(pd->usb_psy, @@ -1617,6 +1702,7 @@ static void usbpd_sm(struct work_struct *w) else if (pd->current_dr == DR_DFP) stop_usb_host(pd); + pd->current_pr = PR_NONE; pd->current_dr = DR_NONE; reset_vdm_state(pd); @@ -1701,6 +1787,7 @@ static void usbpd_sm(struct work_struct *w) if (pd->current_pr == PR_SINK) { usbpd_set_state(pd, PE_SNK_STARTUP); } else if (pd->current_pr == PR_SRC) { + enable_vbus(pd); if (!pd->vconn_enabled && pd->typec_mode == POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE) { @@ -1710,7 +1797,6 @@ static void usbpd_sm(struct work_struct *w) else pd->vconn_enabled = true; } - enable_vbus(pd); usbpd_set_state(pd, PE_SRC_STARTUP); } @@ -2446,6 +2532,20 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) if (pd->typec_mode == typec_mode) return 0; + switch (typec_mode) { + /* Sink states */ + case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: + case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: + case POWER_SUPPLY_TYPEC_SOURCE_HIGH: + if (pd->psy_type == POWER_SUPPLY_TYPE_UNKNOWN) { + usbpd_dbg(&pd->dev, "SNK states but APSD is not done yet.\n"); + return 0; + } + break; + default: + break; + } + pd->typec_mode = typec_mode; usbpd_dbg(&pd->dev, "typec mode:%d present:%d type:%d orientation:%d\n", @@ -2479,16 +2579,6 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) if (pd->current_pr == PR_SINK) return 0; - /* - * Unexpected if not in PR swap; need to force disconnect from - * source so we can turn off VBUS, Vconn, PD PHY etc. - */ - if (pd->current_pr == PR_SRC) { - usbpd_info(&pd->dev, "Forcing disconnect from source mode\n"); - pd->current_pr = PR_NONE; - break; - } - pd->current_pr = PR_SINK; break; @@ -2734,17 +2824,12 @@ static int usbpd_dr_set_property(struct dual_role_phy_instance *dual_role, static int usbpd_dr_prop_writeable(struct dual_role_phy_instance *dual_role, enum dual_role_property prop) { - struct usbpd *pd = dual_role_get_drvdata(dual_role); - switch (prop) { case DUAL_ROLE_PROP_MODE: return 1; case DUAL_ROLE_PROP_DR: case DUAL_ROLE_PROP_PR: - if (pd) - return pd->current_state == PE_SNK_READY || - pd->current_state == PE_SRC_READY; - break; + return 0; default: break; } @@ -3129,6 +3214,81 @@ static ssize_t hard_reset_store(struct device *dev, } static DEVICE_ATTR_WO(hard_reset); +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +static ssize_t org_pdo_h_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct usbpd *pd = dev_get_drvdata(dev); + int i; + ssize_t cnt = 0; + + for (i = 0; i < ARRAY_SIZE(pd->org_received_pdos); i++) { + u32 pdo = pd->org_received_pdos[i]; + + if (pdo == 0) + break; + + cnt += scnprintf(&buf[cnt], PAGE_SIZE - cnt, "PDO %d\n", i + 1); + + if (PD_SRC_PDO_TYPE(pdo) == PD_SRC_PDO_TYPE_FIXED) { + cnt += scnprintf(&buf[cnt], PAGE_SIZE - cnt, + "\tFixed supply\n" + "\tDual-Role Power:%d\n" + "\tUSB Suspend Supported:%d\n" + "\tExternally Powered:%d\n" + "\tUSB Communications Capable:%d\n" + "\tData Role Swap:%d\n" + "\tPeak Current:%d\n" + "\tVoltage:%d (mV)\n" + "\tMax Current:%d (mA)\n", + PD_SRC_PDO_FIXED_PR_SWAP(pdo), + PD_SRC_PDO_FIXED_USB_SUSP(pdo), + PD_SRC_PDO_FIXED_EXT_POWERED(pdo), + PD_SRC_PDO_FIXED_USB_COMM(pdo), + PD_SRC_PDO_FIXED_DR_SWAP(pdo), + PD_SRC_PDO_FIXED_PEAK_CURR(pdo), + PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50, + PD_SRC_PDO_FIXED_MAX_CURR(pdo) * 10); + } else if (PD_SRC_PDO_TYPE(pdo) == PD_SRC_PDO_TYPE_BATTERY) { + cnt += scnprintf(&buf[cnt], PAGE_SIZE - cnt, + "\tBattery supply\n" + "\tMax Voltage:%d (mV)\n" + "\tMin Voltage:%d (mV)\n" + "\tMax Power:%d (mW)\n", + PD_SRC_PDO_VAR_BATT_MAX_VOLT(pdo) * 50, + PD_SRC_PDO_VAR_BATT_MIN_VOLT(pdo) * 50, + PD_SRC_PDO_VAR_BATT_MAX(pdo) * 250); + } else if (PD_SRC_PDO_TYPE(pdo) == PD_SRC_PDO_TYPE_VARIABLE) { + cnt += scnprintf(&buf[cnt], PAGE_SIZE - cnt, + "\tVariable supply\n" + "\tMax Voltage:%d (mV)\n" + "\tMin Voltage:%d (mV)\n" + "\tMax Current:%d (mA)\n", + PD_SRC_PDO_VAR_BATT_MAX_VOLT(pdo) * 50, + PD_SRC_PDO_VAR_BATT_MIN_VOLT(pdo) * 50, + PD_SRC_PDO_VAR_BATT_MAX(pdo) * 10); + } else if (PD_SRC_PDO_TYPE(pdo) == PD_SRC_PDO_TYPE_AUGMENTED) { + cnt += scnprintf(&buf[cnt], PAGE_SIZE - cnt, + "\tProgrammable Power supply\n" + "\tMax Voltage:%d (mV)\n" + "\tMin Voltage:%d (mV)\n" + "\tMax Current:%d (mA)\n", + PD_APDO_MAX_VOLT(pdo) * 100, + PD_APDO_MIN_VOLT(pdo) * 100, + PD_APDO_MAX_CURR(pdo) * 50); + } else { + cnt += scnprintf(&buf[cnt], PAGE_SIZE - cnt, + "Invalid PDO\n"); + } + + buf[cnt++] = '\n'; + } + + return cnt; +} +static DEVICE_ATTR_RO(org_pdo_h); + +#endif static struct attribute *usbpd_attrs[] = { &dev_attr_contract.attr, &dev_attr_initial_pr.attr, @@ -3148,6 +3308,9 @@ static struct attribute *usbpd_attrs[] = { &dev_attr_rdo.attr, &dev_attr_rdo_h.attr, &dev_attr_hard_reset.attr, +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) + &dev_attr_org_pdo_h.attr, +#endif NULL, }; ATTRIBUTE_GROUPS(usbpd); @@ -3234,6 +3397,7 @@ struct usbpd *usbpd_create(struct device *parent) { int ret; struct usbpd *pd; + struct regulator_ocp_notification ocp_ntf; pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) @@ -3297,6 +3461,11 @@ struct usbpd *usbpd_create(struct device *parent) goto put_psy; } + ocp_ntf.notify = usbpd_ocp_notification; + ocp_ntf.ctxt = pd; + ret = regulator_register_ocp_notification(pd->vbus, &ocp_ntf); + + pd->vconn = devm_regulator_get(parent, "vconn"); if (IS_ERR(pd->vconn)) { ret = PTR_ERR(pd->vconn); diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index f30261e543bad6d23d5bb1b88b54506962ef0597..e200c25bc23a79eeee0ad78f370cefe737071912 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -96,8 +96,8 @@ struct usb_pdphy { int msg_tx_discarded_irq; int msg_rx_discarded_irq; - void (*signal_cb)(struct usbpd *pd, enum pd_sig_type sig); - void (*msg_rx_cb)(struct usbpd *pd, enum pd_sop_type sop, + void (*signal_cb)(struct usbpd *pd, enum pd_sig_type type); + void (*msg_rx_cb)(struct usbpd *pd, enum pd_msg_type type, u8 *buf, size_t len); void (*shutdown_cb)(struct usbpd *pd); @@ -401,13 +401,13 @@ int pd_phy_open(struct pd_phy_params *params) } EXPORT_SYMBOL(pd_phy_open); -int pd_phy_signal(enum pd_sig_type sig, unsigned int timeout_ms) +int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms) { u8 val; int ret; struct usb_pdphy *pdphy = __pdphy; - dev_dbg(pdphy->dev, "%s: type %d timeout %u\n", __func__, sig, + dev_dbg(pdphy->dev, "%s: type %d timeout %u\n", __func__, type, timeout_ms); if (!pdphy) { @@ -428,7 +428,7 @@ int pd_phy_signal(enum pd_sig_type sig, unsigned int timeout_ms) usleep_range(2, 3); - val = (sig == CABLE_RESET_SIG ? TX_CONTROL_FRAME_TYPE_CABLE_RESET : 0) + val = (type == CABLE_RESET_SIG ? TX_CONTROL_FRAME_TYPE_CABLE_RESET : 0) | TX_CONTROL_SEND_SIGNAL; ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val); @@ -447,7 +447,7 @@ int pd_phy_signal(enum pd_sig_type sig, unsigned int timeout_ms) if (pdphy->tx_status) return pdphy->tx_status; - if (sig == HARD_RESET_SIG) + if (type == HARD_RESET_SIG) /* Frame filter is reconfigured in pd_phy_open() */ return pdphy_reg_write(pdphy, USB_PDPHY_FRAME_FILTER, 0); @@ -456,15 +456,15 @@ int pd_phy_signal(enum pd_sig_type sig, unsigned int timeout_ms) EXPORT_SYMBOL(pd_phy_signal); int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, - enum pd_sop_type sop, unsigned int timeout_ms) + enum pd_msg_type type, unsigned int timeout_ms) { u8 val; int ret; size_t total_len = data_len + USB_PDPHY_MSG_HDR_LEN; struct usb_pdphy *pdphy = __pdphy; - dev_dbg(pdphy->dev, "%s: hdr %x frame sop_type %d timeout %u\n", - __func__, hdr, sop, timeout_ms); + dev_dbg(pdphy->dev, "%s: hdr %x frame type %d timeout %u\n", + __func__, hdr, type, timeout_ms); if (data && data_len) print_hex_dump_debug("tx data obj:", DUMP_PREFIX_NONE, 32, 4, @@ -518,7 +518,7 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, usleep_range(2, 3); - val = TX_CONTROL_RETRY_COUNT | (sop << 2) | TX_CONTROL_SEND_MSG; + val = TX_CONTROL_RETRY_COUNT | (type << 2) | TX_CONTROL_SEND_MSG; ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val); if (ret) diff --git a/drivers/usb/pd/usbpd.h b/drivers/usb/pd/usbpd.h index 6b323e238aadf78496b0b3fc816251e1b8e3ad2f..108701739f890ede2e9d4be68eae95b76f72ce03 100644 --- a/drivers/usb/pd/usbpd.h +++ b/drivers/usb/pd/usbpd.h @@ -45,7 +45,7 @@ enum pd_sig_type { CABLE_RESET_SIG, }; -enum pd_sop_type { +enum pd_msg_type { SOP_MSG = 0, SOPI_MSG, SOPII_MSG, @@ -61,8 +61,8 @@ enum pd_spec_rev { #define FRAME_FILTER_EN_HARD_RESET BIT(5) struct pd_phy_params { - void (*signal_cb)(struct usbpd *pd, enum pd_sig_type sig); - void (*msg_rx_cb)(struct usbpd *pd, enum pd_sop_type sop, + void (*signal_cb)(struct usbpd *pd, enum pd_sig_type type); + void (*msg_rx_cb)(struct usbpd *pd, enum pd_msg_type type, u8 *buf, size_t len); void (*shutdown_cb)(struct usbpd *pd); enum data_role data_role; @@ -72,9 +72,9 @@ struct pd_phy_params { #if IS_ENABLED(CONFIG_QPNP_USB_PDPHY) int pd_phy_open(struct pd_phy_params *params); -int pd_phy_signal(enum pd_sig_type sig, unsigned int timeout_ms); +int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms); int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, - enum pd_sop_type sop, unsigned int timeout_ms); + enum pd_msg_type type, unsigned int timeout_ms); int pd_phy_update_roles(enum data_role dr, enum power_role pr); void pd_phy_close(void); #else @@ -89,7 +89,7 @@ static inline int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms) } static inline int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, - enum pd_sop_type sop, unsigned int timeout_ms) + enum pd_msg_type type, unsigned int timeout_ms) { return -ENODEV; } diff --git a/drivers/usb/phy/class-dual-role.c b/drivers/usb/phy/class-dual-role.c index 9ef889593ef52ad5dc5e768f02a4472c84f37927..313d17f39050e9526ea4cf06a4da8cdce0e65946 100644 --- a/drivers/usb/phy/class-dual-role.c +++ b/drivers/usb/phy/class-dual-role.c @@ -13,6 +13,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -70,7 +75,15 @@ static char *kstrdupcase(const char *str, gfp_t gfp, bool to_upper) return ret; } -static void dual_role_changed_work(struct work_struct *work); +static void dual_role_changed_work(struct work_struct *work) +{ + struct dual_role_phy_instance *dual_role = + container_of(work, struct dual_role_phy_instance, + changed_work); + + dev_dbg(&dual_role->dev, "%s\n", __func__); + kobject_uevent(&dual_role->dev.kobj, KOBJ_CHANGE); +} void dual_role_instance_changed(struct dual_role_phy_instance *dual_role) { @@ -497,17 +510,6 @@ out: return ret; } -static void dual_role_changed_work(struct work_struct *work) -{ - struct dual_role_phy_instance *dual_role = - container_of(work, struct dual_role_phy_instance, - changed_work); - - dev_dbg(&dual_role->dev, "%s\n", __func__); - sysfs_update_group(&dual_role->dev.kobj, &dual_role_attr_group); - kobject_uevent(&dual_role->dev.kobj, KOBJ_CHANGE); -} - /******************* Module Init ***********************************/ static int __init dual_role_class_init(void) diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 0c912d3950a5f177b5a0e0900b29b18074ca8fb8..39a990313d991d32bbf84a021fc8ff15678ba33c 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -21,6 +21,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index e5f38e42e165738e6bfb2dea3c2c386b541c527d..4afd67617c37bcc086366485cf4ef9667d94f3e1 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -51,6 +56,9 @@ #define QUSB2PHY_PORT_TUNE1 0x23c #define QUSB2PHY_TEST1 0x24C +#define QUSB2PHY_PORT_TUNE2 0x240 +#define QUSB2PHY_PORT_TUNE3 0x244 +#define QUSB2PHY_PORT_TUNE4 0x248 #define QUSB2PHY_1P2_VOL_MIN 1200000 /* uV */ #define QUSB2PHY_1P2_VOL_MAX 1200000 /* uV */ @@ -70,9 +78,39 @@ #define QUSB2PHY_PLL_ANALOG_CONTROLS_ONE 0x0 #define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x4 +#define USB_PHY_HSTX_TRIM 0xF0 /* TUNE1 7:4 */ +#define USB_PHY_HSTX_SR 0x0C /* TUNE1 3:2 */ +#define USB_PHY_HSTX_SR_BIAS 0x03 /* TUNE1 1:0 */ +#define USB_PHY_SEL_EMPH_HALF_WIDTH 0x10 /* TUNE2 4 */ +#define USB_PHY_EN_EMPHASIS 0x0C /* TUNE2 3:2 */ +#define USB_PHY_HS_DISCON_TRIM 0x03 /* TUNE2 1:0 */ +#define USB_PHY_CDR_WIDE 0x80 /* TUNE3 7 */ +#define USB_PHY_CDR_PULSE_SMPL 0x40 /* TUNE3 6 */ +#define USB_PHY_TX2RX_DLY 0x3F /* TUNE3 5:0 */ +#define USB_PHY_HANDOFF_PHSEL 0xE0 /* TUNE4 7:5 */ +#define USB_PHY_FORCE_HSRX_ALWAYS_ON 0x10 /* TUNE4 4 */ +#define USB_PHY_SQ_FILTER_DIS 0x08 /* TUNE4 3 */ +#define USB_PHY_SQ_LEVEL 0x07 /* TUNE4 2:0 */ + unsigned int phy_tune1; +unsigned int phy_tune2; +unsigned int phy_tune3; +unsigned int phy_tune4; +unsigned int phy_host_tune1; +unsigned int phy_host_tune2; module_param(phy_tune1, uint, S_IRUGO | S_IWUSR); +module_param(phy_tune2, uint, S_IRUGO | S_IWUSR); +module_param(phy_tune3, uint, S_IRUGO | S_IWUSR); +module_param(phy_tune4, uint, S_IRUGO | S_IWUSR); +module_param(phy_host_tune1, uint, S_IRUGO | S_IWUSR); +module_param(phy_host_tune2, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(phy_tune1, "QUSB PHY v2 TUNE1"); +MODULE_PARM_DESC(phy_tune2, "QUSB PHY v2 TUNE2"); +MODULE_PARM_DESC(phy_tune3, "QUSB PHY v2 TUNE3"); +MODULE_PARM_DESC(phy_tune4, "QUSB PHY v2 TUNE4"); +MODULE_PARM_DESC(phy_host_tune1, "QUSB PHY HOST v2 TUNE1"); +MODULE_PARM_DESC(phy_host_tune2, "QUSB PHY HOST v2 TUNE2"); + struct qusb_phy { struct usb_phy phy; @@ -98,8 +136,10 @@ struct qusb_phy { int *qusb_phy_host_init_seq; u32 tune_val; + u32 host_tune_val; int efuse_bit_pos; int efuse_num_of_bits; + u32 efuse_offset; int power_enabled_ref; bool clocks_enabled; @@ -380,14 +420,16 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value) return ret; } -static void qusb_phy_get_tune1_param(struct qusb_phy *qphy) +static u32 qusb_phy_get_tune1_param(struct qusb_phy *qphy) { u8 reg; u32 bit_mask = 1; + u32 tune_val; - pr_debug("%s(): num_of_bits:%d bit_pos:%d\n", __func__, + pr_debug("%s(): num_of_bits:%d bit_pos:%d offset:%d\n", __func__, qphy->efuse_num_of_bits, - qphy->efuse_bit_pos); + qphy->efuse_bit_pos, + qphy->efuse_offset); /* get bit mask based on number of bits to use with efuse reg */ bit_mask = (bit_mask << qphy->efuse_num_of_bits) - 1; @@ -396,18 +438,22 @@ static void qusb_phy_get_tune1_param(struct qusb_phy *qphy) * if efuse reg is updated (i.e non-zero) then use it to program * tune parameters */ - qphy->tune_val = readl_relaxed(qphy->efuse_reg); + tune_val = readl_relaxed(qphy->efuse_reg); pr_debug("%s(): bit_mask:%d efuse based tune1 value:%d\n", - __func__, bit_mask, qphy->tune_val); + __func__, bit_mask, tune_val); - qphy->tune_val = TUNE_VAL_MASK(qphy->tune_val, - qphy->efuse_bit_pos, bit_mask); + tune_val = TUNE_VAL_MASK(tune_val, qphy->efuse_bit_pos, bit_mask); reg = readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE1); - if (qphy->tune_val) { + if (tune_val) { + tune_val += qphy->efuse_offset; + if ((s32)tune_val < 0) + tune_val = 0x00; + else if ((s32)tune_val > 0x0f) + tune_val = 0x0f; reg = reg & 0x0f; - reg |= (qphy->tune_val << 4); + reg |= (tune_val << 4); } - qphy->tune_val = reg; + return reg; } static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt, @@ -424,6 +470,75 @@ static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt, } } +static inline u32 msm_usb_read_reg_field(void *base, u32 offset, const u32 mask) +{ + u32 shift = find_first_bit((void *)&mask, 32); + u32 val = readb_relaxed(base + offset); + val &= mask; /* clear other bits */ + val >>= shift; + return val; +} + +static void msm_qphy_param_output(struct usb_phy *phy) +{ + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + + /* PORT_TUNE1 */ + dev_dbg(phy->dev, "PORT_TUNE1:0x%02x\n", + readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE1)); + dev_dbg(phy->dev, " :HSTX_TRIM \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE1, USB_PHY_HSTX_TRIM)); + dev_dbg(phy->dev, " :HSTX_SR \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE1, USB_PHY_HSTX_SR)); + dev_dbg(phy->dev, " :HSTX_SR_BIAS \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE1, USB_PHY_HSTX_SR_BIAS)); + + /* PORT_TUNE2 */ + dev_dbg(phy->dev, "PORT_TUNE2:0x%02x\n", + readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE2)); + dev_dbg(phy->dev, " :SEL_EMPH_HALF_WIDTH \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE2, USB_PHY_SEL_EMPH_HALF_WIDTH)); + dev_dbg(phy->dev, " :EN_EMPHASIS \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE2, USB_PHY_EN_EMPHASIS)); + dev_dbg(phy->dev, " :HS_DISCON_TRIM \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE2, USB_PHY_HS_DISCON_TRIM)); + + /* PORT_TUNE3 */ + dev_dbg(phy->dev, "PORT_TUNE3:0x%02x\n", + readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE3)); + dev_dbg(phy->dev, " :CDR_WIDE \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE3, USB_PHY_CDR_WIDE)); + dev_dbg(phy->dev, " :CDR_PULSE_SMPL \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE3, USB_PHY_CDR_PULSE_SMPL)); + dev_dbg(phy->dev, " :TX2RX_DLY \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE3, USB_PHY_TX2RX_DLY)); + + /* PORT_TUNE4 */ + dev_dbg(phy->dev, "PORT_TUNE4:0x%02x\n", + readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE4)); + dev_dbg(phy->dev, " :HANDOFF_PHSEL \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE4, USB_PHY_HANDOFF_PHSEL)); + dev_dbg(phy->dev, " :FORCE_HSRX_ALWAYS_ON \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE4, USB_PHY_FORCE_HSRX_ALWAYS_ON)); + dev_dbg(phy->dev, " :SQ_FILTER_DIS \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE4, USB_PHY_SQ_FILTER_DIS)); + dev_dbg(phy->dev, " :SQ_LEVEL \t0x%02x\n", + msm_usb_read_reg_field(qphy->base, + QUSB2PHY_PORT_TUNE4, USB_PHY_SQ_LEVEL)); +} + static void qusb_phy_host_init(struct usb_phy *phy) { u8 reg; @@ -444,6 +559,32 @@ static void qusb_phy_host_init(struct usb_phy *phy) qusb_phy_write_seq(qphy->base, qphy->qusb_phy_host_init_seq, qphy->host_init_seq_len, 0); + if (qphy->efuse_reg) { + if (!qphy->host_tune_val) + qphy->host_tune_val = qusb_phy_get_tune1_param(qphy); + + pr_debug("%s(): Programming host TUNE1 parameter as:%x\n", + __func__, qphy->host_tune_val); + writel_relaxed(qphy->host_tune_val, + qphy->base + QUSB2PHY_PORT_TUNE1); + } + + /* If phy_tune1 modparam set, override tune1 value */ + if (phy_host_tune1) { + pr_debug("%s(): (modparam) HOST_TUNE1 val:0x%02x\n", + __func__, phy_host_tune1); + writel_relaxed(phy_host_tune1, + qphy->base + QUSB2PHY_PORT_TUNE1); + } + /* If phy_tune2 modparam set, override tune2 value */ + if (phy_host_tune2) { + pr_debug("%s(): (modparam) HOST TUNE2 val:0x%02x\n", + __func__, phy_host_tune2); + writel_relaxed(phy_host_tune2, + qphy->base + QUSB2PHY_PORT_TUNE2); + } + msm_qphy_param_output(phy); + /* Ensure above write is completed before turning ON ref clk */ wmb(); @@ -520,7 +661,7 @@ static int qusb_phy_init(struct usb_phy *phy) qphy->init_seq_len, 0); if (qphy->efuse_reg) { if (!qphy->tune_val) - qusb_phy_get_tune1_param(qphy); + qphy->tune_val = qusb_phy_get_tune1_param(qphy); pr_debug("%s(): Programming TUNE1 parameter as:%x\n", __func__, qphy->tune_val); @@ -535,6 +676,28 @@ static int qusb_phy_init(struct usb_phy *phy) writel_relaxed(phy_tune1, qphy->base + QUSB2PHY_PORT_TUNE1); } + /* If phy_tune2 modparam set, override tune2 value */ + if (phy_tune2) { + pr_debug("%s(): (modparam) TUNE2 val:0x%02x\n", + __func__, phy_tune2); + writel_relaxed(phy_tune2, + qphy->base + QUSB2PHY_PORT_TUNE2); + } + /* If phy_tune3 modparam set, override tune3 value */ + if (phy_tune3) { + pr_debug("%s(): (modparam) TUNE3 val:0x%02x\n", + __func__, phy_tune3); + writel_relaxed(phy_tune3, + qphy->base + QUSB2PHY_PORT_TUNE3); + } + /* If phy_tune4 modparam set, override tune4 value */ + if (phy_tune4) { + pr_debug("%s(): (modparam) TUNE4 val:0x%02x\n", + __func__, phy_tune4); + writel_relaxed(phy_tune4, + qphy->base + QUSB2PHY_PORT_TUNE4); + } + msm_qphy_param_output(phy); /* ensure above writes are completed before re-enabling PHY */ wmb(); @@ -652,16 +815,13 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) writel_relaxed(intr_mask, qphy->base + QUSB2PHY_INTR_CTRL); - if (linestate & (LINESTATE_DP | LINESTATE_DM)) { - - /* enable phy auto-resume */ - writel_relaxed(0x91, + /* enable phy auto-resume */ + writel_relaxed(0x91, qphy->base + QUSB2PHY_TEST1); - /* flush the previous write before next write */ - wmb(); - writel_relaxed(0x90, - qphy->base + QUSB2PHY_TEST1); - } + /* flush the previous write before next write */ + wmb(); + writel_relaxed(0x90, + qphy->base + QUSB2PHY_TEST1); dev_dbg(phy->dev, "%s: intr_mask = %x\n", __func__, intr_mask); @@ -886,6 +1046,12 @@ static int qusb_phy_probe(struct platform_device *pdev) &qphy->efuse_num_of_bits); } + if (!ret) { + ret = of_property_read_u32(dev->of_node, + "qcom,efuse-offset", + &qphy->efuse_offset); + } + if (ret) { dev_err(dev, "DT Value for efuse is invalid.\n"); diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c index be63c6c0a86abca74448fed822cba43017162b27..bd2722e8fc480becc82a4ff92717e3e6e22e97ed 100644 --- a/drivers/usb/phy/phy-msm-qusb.c +++ b/drivers/usb/phy/phy-msm-qusb.c @@ -74,6 +74,10 @@ #define QUSB2PHY_PORT_TUNE4 0x8C #define QUSB2PHY_PORT_TUNE5 0x90 +/* In case Efuse register shows zero, use this value */ +#define TUNE2_DEFAULT_HIGH_NIBBLE 0xB +#define TUNE2_DEFAULT_LOW_NIBBLE 0x3 + /* Get TUNE2's high nibble value read from efuse */ #define TUNE2_HIGH_NIBBLE_VAL(val, pos, mask) ((val >> pos) & mask) @@ -143,7 +147,6 @@ struct qusb_phy { u32 tune2_val; int tune2_efuse_bit_pos; int tune2_efuse_num_of_bits; - int tune2_efuse_correction; bool power_enabled; bool clocks_enabled; @@ -430,7 +433,6 @@ static void qusb_phy_get_tune2_param(struct qusb_phy *qphy) { u8 num_of_bits; u32 bit_mask = 1; - u8 reg_val; pr_debug("%s(): num_of_bits:%d bit_pos:%d\n", __func__, qphy->tune2_efuse_num_of_bits, @@ -444,8 +446,9 @@ static void qusb_phy_get_tune2_param(struct qusb_phy *qphy) /* * Read EFUSE register having TUNE2 parameter's high nibble. - * If efuse register shows value as 0x0, then use previous value - * as it is. Otherwise use efuse register based value for this purpose. + * If efuse register shows value as 0x0, then use default value + * as 0xB as high nibble. Otherwise use efuse register based + * value for this purpose. */ qphy->tune2_val = readl_relaxed(qphy->tune2_efuse_reg); pr_debug("%s(): bit_mask:%d efuse based tune2 value:%d\n", @@ -454,24 +457,12 @@ static void qusb_phy_get_tune2_param(struct qusb_phy *qphy) qphy->tune2_val = TUNE2_HIGH_NIBBLE_VAL(qphy->tune2_val, qphy->tune2_efuse_bit_pos, bit_mask); - /* Update higher nibble of TUNE2 value for better rise/fall times */ - if (qphy->tune2_efuse_correction && qphy->tune2_val) { - if (qphy->tune2_efuse_correction > 5 || - qphy->tune2_efuse_correction < -10) - pr_warn("Correction value is out of range : %d\n", - qphy->tune2_efuse_correction); - else - qphy->tune2_val = qphy->tune2_val + - qphy->tune2_efuse_correction; - } - - reg_val = readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE2); - if (qphy->tune2_val) { - reg_val &= 0x0f; - reg_val |= (qphy->tune2_val << 4); - } + if (!qphy->tune2_val) + qphy->tune2_val = TUNE2_DEFAULT_HIGH_NIBBLE; - qphy->tune2_val = reg_val; + /* Get TUNE2 byte value using high and low nibble value */ + qphy->tune2_val = ((qphy->tune2_val << 0x4) | + TUNE2_DEFAULT_LOW_NIBBLE); } static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt, @@ -579,7 +570,7 @@ static int qusb_phy_init(struct usb_phy *phy) * and try to read EFUSE value only once i.e. not every USB * cable connect case. */ - if (qphy->tune2_efuse_reg && !tune2) { + if (qphy->tune2_efuse_reg) { if (!qphy->tune2_val) qusb_phy_get_tune2_param(qphy); @@ -938,9 +929,6 @@ static int qusb_phy_probe(struct platform_device *pdev) "qcom,tune2-efuse-num-bits", &qphy->tune2_efuse_num_of_bits); } - of_property_read_u32(dev->of_node, - "qcom,tune2-efuse-correction", - &qphy->tune2_efuse_correction); if (ret) { dev_err(dev, "DT Value for tune2 efuse is invalid.\n"); diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index 2bc3c6fa417abc4ae80764a4d8132d35ea0b113a..c5cf46736957976cd65b9405bdd50d46723d1c8a 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -11,6 +11,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -57,6 +62,24 @@ enum ldo_levels { /* port select mux: 1 - sw control. 0 - HW control*/ #define SW_PORTSELECT_MX BIT(1) +#define SSUSB3PHY_TXA_DRV_LVL 0x21c +#define SSUSB3PHY_TXB_DRV_LVL 0x61c +#define SSUSB3PHY_TXA_EMP_POST1_LVL 0x20c +#define SSUSB3PHY_TXB_EMP_POST1_LVL 0x60c + +unsigned int ssphy_txa_drv_lvl; +unsigned int ssphy_txb_drv_lvl; +unsigned int ssphy_txa_emp_post1_lvl; +unsigned int ssphy_txb_emp_post1_lvl; +module_param(ssphy_txa_drv_lvl, uint, S_IRUGO | S_IWUSR); +module_param(ssphy_txb_drv_lvl, uint, S_IRUGO | S_IWUSR); +module_param(ssphy_txa_emp_post1_lvl, uint, S_IRUGO | S_IWUSR); +module_param(ssphy_txb_emp_post1_lvl, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ssphy_txa_drv_lvl, "SSUSB3PHY QSERDES TXA DRV LVL"); +MODULE_PARM_DESC(ssphy_txb_drv_lvl, "SSUSB3PHY QSERDES TXB DRV LVL"); +MODULE_PARM_DESC(ssphy_txa_emp_post1_lvl, "SSUSB3PHY QSERDES TXA EMP POST1 LVL"); +MODULE_PARM_DESC(ssphy_txb_emp_post1_lvl, "SSUSB3PHY QSERDES TXB EMP POST1 LVL"); + enum qmp_phy_rev_reg { USB3_PHY_PCS_STATUS, USB3_PHY_AUTONOMOUS_MODE_CTRL, @@ -149,17 +172,15 @@ static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy, if (enable) { msm_ssusb_qmp_clr_lfps_rxterm_int(phy); - val = readb_relaxed(phy->base + autonomous_mode_offset); - val |= ARCVR_DTCT_EN; if (phy->phy.flags & DEVICE_IN_SS_MODE) { + val = + readb_relaxed(phy->base + autonomous_mode_offset); + val |= ARCVR_DTCT_EN; val |= ALFPS_DTCT_EN; val &= ~ARCVR_DTCT_EVENT_SEL; - } else { - val &= ~ALFPS_DTCT_EN; - val |= ARCVR_DTCT_EVENT_SEL; + writeb_relaxed(val, phy->base + autonomous_mode_offset); } - writeb_relaxed(val, phy->base + autonomous_mode_offset); /* clamp phy level shifter to perform autonomous detection */ writel_relaxed(0x1, phy->vls_clamp_reg); } else { @@ -263,6 +284,21 @@ disable_fpc_redrive: return rc < 0 ? rc : 0; } +static void msm_ssphy_param_output(struct usb_phy *uphy) +{ + struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, + phy); + + dev_dbg(uphy->dev, "SS_USB3PHY_QSERDES_TXA_TX_DEV_LVL:0x%02x\n", + readb_relaxed(phy->base + SSUSB3PHY_TXA_DRV_LVL)); + dev_dbg(uphy->dev, "SS_USB3PHY_QSERDES_TXB_TX_DEV_LVL:0x%02x\n", + readb_relaxed(phy->base + SSUSB3PHY_TXB_DRV_LVL)); + dev_dbg(uphy->dev, "SS_USB3PHY_QSERDES_TXA_TX_EMP_POST1_LVL:0x%02x\n", + readb_relaxed(phy->base + SSUSB3PHY_TXA_EMP_POST1_LVL)); + dev_dbg(uphy->dev, "SS_USB3PHY_QSERDES_TXB_TX_EMP_POST1_LVL:0x%02x\n", + readb_relaxed(phy->base + SSUSB3PHY_TXB_EMP_POST1_LVL)); +} + static int configure_phy_regs(struct usb_phy *uphy, const struct qmp_reg_val *reg) { @@ -280,6 +316,23 @@ static int configure_phy_regs(struct usb_phy *uphy, usleep_range(reg->delay, reg->delay + 10); reg++; } + + /* ssusb phy dynamic set */ + if (ssphy_txa_drv_lvl) + writel_relaxed(ssphy_txa_drv_lvl, + phy->base + SSUSB3PHY_TXA_DRV_LVL); + if (ssphy_txb_drv_lvl) + writel_relaxed(ssphy_txb_drv_lvl, + phy->base + SSUSB3PHY_TXB_DRV_LVL); + if (ssphy_txa_emp_post1_lvl) + writel_relaxed(ssphy_txa_emp_post1_lvl, + phy->base + SSUSB3PHY_TXA_EMP_POST1_LVL); + if (ssphy_txb_emp_post1_lvl) + writel_relaxed(ssphy_txb_emp_post1_lvl, + phy->base + SSUSB3PHY_TXB_EMP_POST1_LVL); + + /* parameter output */ + msm_ssphy_param_output(uphy); return 0; } diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index f1360f20ffe48e1cdd523b18d2c0b19b8c778e1e..738b50a88736008c0607998ee3f0f947814b0b95 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -15,6 +15,11 @@ * 02110-1301, USA. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index b0dc6da3d97048dfbec46def9465dbb99c4c4662..33cec50978b8f9f0d91e287932cb0d8aeeeb089e 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -134,7 +134,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */ { USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */ { USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */ - { USB_DEVICE(0x10C4, 0x8A5E) }, /* CEL EM3588 ZigBee USB Stick Long Range */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ebe51f11105d8889d6144a72bbf719f14e4b1103..3bf61acfc26b9cfdee5496feeb64bdbcfd58015c 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1877,10 +1877,6 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&four_g_w100_blacklist }, { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) }, - { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9801, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, - { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9803, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) }, { USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) }, { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) }, diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 652b4334b26dd62eb966bda17d3a52251471587c..fd509ed6cf7065725c097ab1bc4eac84359be1f6 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -158,7 +158,6 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x1199, 0x9056)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9060)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9061)}, /* Sierra Wireless Modem */ - {DEVICE_SWI(0x1199, 0x9063)}, /* Sierra Wireless EM7305 */ {DEVICE_SWI(0x1199, 0x9070)}, /* Sierra Wireless MC74xx */ {DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx */ {DEVICE_SWI(0x1199, 0x9078)}, /* Sierra Wireless EM74xx */ diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 640a2e2ec04d68c38ec02bc39d8eb9d8c4b85b96..bcb72048ef7d6821784e5fb2955be879c9028d75 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -24,6 +24,11 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* IMPORTANT NOTE: This file must be included in another file which does * the following thing for it to work: diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index af10f7b131a4920ec96190b954d43996a7af9e4d..44ab43fc4fcc71c8f7732e5c74120ae278b0b89f 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -262,11 +262,7 @@ void stub_device_cleanup_urbs(struct stub_device *sdev) kmem_cache_free(stub_priv_cache, priv); kfree(urb->transfer_buffer); - urb->transfer_buffer = NULL; - kfree(urb->setup_packet); - urb->setup_packet = NULL; - usb_free_urb(urb); } } diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c index 021003c4de53e447ea2da37e6bc9549f2c74f620..dbcabc9dbe0dc81c499902038515857d242d3fd5 100644 --- a/drivers/usb/usbip/stub_tx.c +++ b/drivers/usb/usbip/stub_tx.c @@ -28,11 +28,7 @@ static void stub_free_priv_and_urb(struct stub_priv *priv) struct urb *urb = priv->urb; kfree(urb->setup_packet); - urb->setup_packet = NULL; - kfree(urb->transfer_buffer); - urb->transfer_buffer = NULL; - list_del(&priv->list); kmem_cache_free(stub_priv_cache, priv); usb_free_urb(urb); diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 81b2b9f808b59af531d98faf72bdcdca0937fa42..7fbe19d5279e5c11159f141fdd20b6a3ac7ff568 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -215,19 +215,14 @@ done: static inline void hub_descriptor(struct usb_hub_descriptor *desc) { - int width; - memset(desc, 0, sizeof(*desc)); desc->bDescriptorType = USB_DT_HUB; + desc->bDescLength = 9; desc->wHubCharacteristics = cpu_to_le16( HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM); - desc->bNbrPorts = VHCI_NPORTS; - BUILD_BUG_ON(VHCI_NPORTS > USB_MAXCHILDREN); - width = desc->bNbrPorts / 8 + 1; - desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * width; - memset(&desc->u.hs.DeviceRemovable[0], 0, width); - memset(&desc->u.hs.DeviceRemovable[width], 0xff, width); + desc->u.hs.DeviceRemovable[0] = 0xff; + desc->u.hs.DeviceRemovable[1] = 0xff; } static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 34e4b3ad8b92a89e0a8b6afe493a85c8ab5a7257..1a9f18b40be6228755b28cb4d639e9ff96186f63 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -1163,10 +1163,6 @@ static int tce_iommu_attach_group(void *iommu_data, /* pr_debug("tce_vfio: Attaching group #%u to iommu %p\n", iommu_group_id(iommu_group), iommu_group); */ table_group = iommu_group_get_iommudata(iommu_group); - if (!table_group) { - ret = -ENODEV; - goto unlock_exit; - } if (tce_groups_attached(container) && (!table_group->ops || !table_group->ops->take_ownership || diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index daca9e6a2bb31590071cfc7100e4c1ee8ca4f1ec..7f6bc81aa31bc64dfbbea00170afbc9da5a8af67 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -8,6 +8,11 @@ * published by the Free Software Foundation. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c index 9362424c2340490585fe02e4dfe950f53f2097af..4eb7412c4d1386fd06b2a95009044fe2073bb223 100644 --- a/drivers/video/fbdev/amba-clcd.c +++ b/drivers/video/fbdev/amba-clcd.c @@ -10,6 +10,11 @@ * * ARM PrimeCell PL110 Color LCD Controller */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/drivers/video/fbdev/msm/Kconfig b/drivers/video/fbdev/msm/Kconfig index 03ee89ad0d999e2e3940be0f8ba29c3e6fcb8fe9..6ae83669d71a775d82452157259eb453d6b80116 100644 --- a/drivers/video/fbdev/msm/Kconfig +++ b/drivers/video/fbdev/msm/Kconfig @@ -61,6 +61,15 @@ config FB_MSM_MDSS_WRITEBACK The MDSS Writeback Panel provides support for routing the output of MDSS frame buffer driver and MDP processing to memory. +config FB_MSM_MDSS_SPECIFIC_PANEL + depends on FB_MSM_MDSS + bool + prompt "MDSS Specific panel" + default n + ---help--- + The MDSS Specific Panel provides support for specific panel driver + file. + config FB_MSM_MDSS_HDMI_PANEL depends on FB_MSM_MDSS select MSM_EXT_DISPLAY diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile index e101b873f361faa75dfb7b2e25edb16f658c4243..37d278ac161efc39ecf28b8ac69fb4e868e02834 100644 --- a/drivers/video/fbdev/msm/Makefile +++ b/drivers/video/fbdev/msm/Makefile @@ -32,6 +32,10 @@ obj-$(CONFIG_DEBUG_FS) += mdss_debug.o mdss_debug_xlog.o endif mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o mdss_dsi_cmd.o mdss_dsi_status.o +ifeq ($(CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL),y) +mdss-dsi-objs += mdss_dsi_panel_driver.o +mdss-dsi-objs += mdss_dsi_panel_debugfs.o +endif mdss-dsi-objs += mdss_dsi_panel.o mdss-dsi-objs += msm_mdss_io_8974.o mdss-dsi-objs += mdss_dsi_phy.o @@ -63,4 +67,7 @@ obj-$(CONFIG_FB_MSM_QPIC) += mdss-qpic.o obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o mdss_util.o +ifeq ($(CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL),y) +obj-$(CONFIG_FB_MSM_MDSS) += incell.o +endif obj-$(CONFIG_COMPAT) += mdss_compat_utils.o diff --git a/drivers/video/fbdev/msm/incell.c b/drivers/video/fbdev/msm/incell.c new file mode 100644 index 0000000000000000000000000000000000000000..c5f0b215fc67379fbe65bbcbd012f72ba4bcedbf --- /dev/null +++ b/drivers/video/fbdev/msm/incell.c @@ -0,0 +1,650 @@ +/* drivers/video/fbdev/msm/incell.c + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "mdss_fb.h" +#include "mdss_mdp.h" +#include "mdss_dsi.h" +#include "mdss_dsi_panel_driver.h" + +struct incell_ctrl *incell; +struct incell_ctrl incell_buf; + +struct incell_ctrl *incell_get_info(void) +{ + return incell; +} + +int incell_get_power_status(incell_pw_status *power_status) +{ + struct incell_ctrl *incell = incell_get_info(); + + if (!incell) { + pr_err("%s: Invalid incell data\n", __func__); + return INCELL_ERROR; + } + + pr_debug("%s: status = 0x%x\n", __func__, (incell->state)); + + if (mdss_dsi_panel_driver_is_power_on(incell->state)) { + power_status->display_power = INCELL_POWER_ON; + power_status->touch_power = INCELL_POWER_ON; + } else { + power_status->display_power = INCELL_POWER_OFF; + power_status->touch_power = INCELL_POWER_OFF; + } + + return INCELL_OK; +} + +static int incell_driver_power_off(struct fb_info *info) +{ + int ret = INCELL_ERROR; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_ctl *ctl = NULL; + struct mdss_panel_data *pdata = NULL; + struct msm_fb_data_type *mfd = NULL; + struct incell_ctrl *incell = incell_get_info(); + + if (!incell) { + pr_err("%s: Invalid incell data\n", __func__); + return ret; + } + + if (!mdata) { + pr_err("%s: Invalid mdata\n", __func__); + return ret; + } + + ctl = mdata->ctl_off; + if (!ctl) { + pr_err("%s: Invalid ctl data\n", __func__); + return ret; + } + + pdata = ctl->panel_data; + if (!pdata) { + pr_err("%s: Invalid panel data\n", __func__); + return ret; + } + + mfd = (struct msm_fb_data_type *)info->par; + if (!mfd) { + pr_err("%s: Invalid msm data\n", __func__); + return ret; + } + + if (!mdss_fb_is_power_on(mfd)) { + mdss_dsi_panel_driver_power_off_ctrl(incell); + mdss_dsi_panel_driver_state_change_off(incell); + + ret = mdss_dsi_panel_driver_power_off(pdata); + if (ret) { + pr_err("%s: Failed to power off ret=%d\n", + __func__, ret); + ret = INCELL_ERROR; + return ret; + } + } else { + ret = info->fbops->fb_blank(FB_BLANK_POWERDOWN, info); + if (ret) { + pr_err("%s: fb_blank(blank) FAIL ret=%d\n", + __func__, ret); + ret = INCELL_ERROR; + return ret; + } + } + + ret = INCELL_OK; + return ret; +} + +static int incell_driver_send_power_on_seq(struct mdss_panel_data *pdata) +{ + int ret = INCELL_ERROR; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_specific_pdata *spec_pdata = NULL; + + ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); + spec_pdata = ctrl_pdata->spec_pdata; + + if (!ctrl_pdata || !spec_pdata) { + pr_err("%s: Invalid input data\n", __func__); + goto end; + } + + ret = mdss_dsi_panel_driver_power_on(pdata); + if (ret) { + pr_err("%s: Failed to power on ret=%d\n", __func__, ret); + ret = INCELL_ERROR; + goto end; + } + + if (mdss_dsi_pinctrl_set_state(ctrl_pdata, true)) + pr_debug("%s: reset enable: pinctrl not enabled\n", + __func__); + mdss_dsi_panel_reset(pdata, 1); + + if (incell->incell_intf_operation == INCELL_TOUCH_RUN && + incell->intf_mode == INCELL_DISPLAY_HW_RESET) { + mdss_dsi_panel_driver_reset_touch(pdata, 1); + mdss_dsi_panel_driver_state_change_on(incell); + } else { + if (!ctrl_pdata->on) + goto end; + + ret = ctrl_pdata->on(pdata); + if (ret) { + pr_err("%s: Failed to send on ret=%d\n", + __func__, ret); + ret = INCELL_ERROR; + goto end; + } + + if (!ctrl_pdata->post_panel_on) + goto end; + + ret = ctrl_pdata->post_panel_on(pdata); + if (ret) { + pr_err("%s: Failed to send post-on ret=%d\n", + __func__, ret); + ret = INCELL_ERROR; + goto end; + } + } + ret = INCELL_OK; +end: + return ret; +} + +static int incell_driver_send_power_on_fb(struct fb_info *info) +{ + int ret = INCELL_ERROR; + + if (!(info->fbops->fb_open) || !(info->fbops->fb_blank) + || !(info->fbops->fb_release)) { + pr_err("%s: Invalid operations\n", __func__); + goto end; + } + + ret = info->fbops->fb_blank(FB_BLANK_UNBLANK, info); + if (ret) { + pr_err("%s: fb_blank(blank) FAIL ret=%d\n", + __func__, ret); + ret = INCELL_ERROR; + goto end; + } + ret = INCELL_OK; +end: + return ret; +} + +static int incell_driver_power_on(struct fb_info *info) +{ + int ret = INCELL_ERROR; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_ctl *ctl = NULL; + struct mdss_panel_data *pdata = NULL; + struct msm_fb_data_type *mfd = NULL; + struct fb_specific_data *spec_mfd = NULL; + + if (!mdata) { + pr_err("%s: Invalid mdata\n", __func__); + goto end; + } + + ctl = mdata->ctl_off; + if (!ctl) { + pr_err("%s: Invalid ctl data\n", __func__); + goto end; + } + + pdata = ctl->panel_data; + if (!pdata) { + pr_err("%s: Invalid panel data\n", __func__); + goto end; + } + + mfd = (struct msm_fb_data_type *)info->par; + if (!mfd) { + pr_err("%s: Invalid msm data\n", __func__); + goto end; + } + spec_mfd = &mfd->spec_mfd; + + if (mdss_fb_is_power_on(mfd)) + ret = incell_driver_send_power_on_seq(pdata); + else + ret = incell_driver_send_power_on_fb(info); + + if (spec_mfd->off_sts) + spec_mfd->off_sts = false; + +end: + return ret; +} + +static int incell_display_hw_reset(struct incell_ctrl *incell, + struct fb_info *info) +{ + int ret = INCELL_ERROR; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_ctl *ctl = NULL; + struct mdss_panel_data *pdata = NULL; + + if (!incell) { + pr_err("%s: Invalid incell data\n", __func__); + goto end; + } + + if (!mdata) { + pr_err("%s: Invalid mdata\n", __func__); + goto end; + } + + ctl = mdata->ctl_off; + if (!ctl) { + pr_err("%s: Invalid ctl data\n", __func__); + goto end; + } + + pdata = ctl->panel_data; + if (!pdata) { + pr_err("%s: Invalid panel data\n", __func__); + goto end; + } + + /* Power off if LCD is on. */ + if (mdss_dsi_panel_driver_is_power_on(incell->state)) + /* + * It calls directly power off to DSI layer, + * the case of FB off. + */ + ret = incell_driver_power_off(info); + else + pr_debug("%s: Skip LCD off 0x%x\n", __func__, + (incell->state)); + + if (!mdss_dsi_panel_driver_is_system_on(incell->state) + && !mdss_dsi_panel_driver_is_power_on(incell->state)) { + pr_debug("%s: LCD on in DSI layer. sts:0x%x\n", __func__, + (incell->state)); + ret = incell_driver_send_power_on_seq(pdata); + } else { + pr_debug("%s: LCD on in FB layer. sts:0x%x\n", __func__, + (incell->state)); + ret = incell_driver_send_power_on_fb(info); + } + + ret = INCELL_OK; +end: + return ret; +} + +static int incell_display_off(struct incell_ctrl *incell, + struct fb_info *info) +{ + int ret = INCELL_ERROR; + + if (!mdss_dsi_panel_driver_is_power_on(incell->state)) { + pr_err("%s: LCD is already off. sts:0x%x\n", + __func__, (incell->state)); + ret = INCELL_EALREADY; + } else { + pr_debug("%s: incell panel sts:0x%x\n", __func__, + (incell->state)); + } + + if (ret == INCELL_EALREADY) { + pr_err("%s: Already power off ret=%d\n", __func__, ret); + return ret; + } + + ret = incell_driver_power_off(info); + return ret; +} + +int incell_control_mode(incell_intf_mode mode, bool force) +{ + int ret = INCELL_ERROR; + struct fb_info *info = NULL; + struct msm_fb_data_type *mfd = NULL; + struct fb_specific_data *spec_mfd = NULL; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_ctl *ctl = NULL; + struct mdss_panel_data *pdata = NULL; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_specific_pdata *spec_pdata = NULL; + struct incell_ctrl *incell = incell_get_info(); + + pr_notice("%s: START - %s:%s\n", __func__, + ((mode == INCELL_DISPLAY_HW_RESET) ? "INCELL_DISPLAY_HW_RESET" : + ((mode == INCELL_DISPLAY_OFF) ? "INCELL_DISPLAY_OFF" : + "INCELL_DISPLAY_ON")), + ((force) ? "force" : "unforce")); + + if (!incell) { + pr_err("%s: Invalid incell data\n", __func__); + return ret; + } + + info = registered_fb[0]; + if (!info) { + pr_err("%s: Invalid fb data\n", __func__); + return ret; + } + + if (!(info->fbops->fb_blank) || !(info->fbops->fb_release) + || !(info->fbops->fb_open)) { + pr_err("%s: Invalid operations\n", __func__); + return ret; + } + + if (!mdata) { + pr_err("%s: Invalid mdata\n", __func__); + return ret; + } + + ctl = mdata->ctl_off; + if (!ctl) { + pr_err("%s: Invalid ctl data\n", __func__); + return ret; + } + + pdata = ctl->panel_data; + if (!pdata) { + pr_err("%s: Invalid panel data\n", __func__); + return ret; + } + + mfd = (struct msm_fb_data_type *)info->par; + if (!mfd) { + pr_err("%s: Invalid msm data\n", __func__); + return ret; + } + spec_mfd = &mfd->spec_mfd; + + ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); + spec_pdata = ctrl_pdata->spec_pdata; + + if (!ctrl_pdata || !spec_pdata) { + pr_err("%s: Invalid input data\n", __func__); + return ret; + } + + /* + * It returns "INCELL_ALREADY_LOCKED" + * the case of not setting "INCELL_FORCE" flag. + */ + if (mdss_dsi_panel_driver_is_power_lock(incell->state)) { + if (force == INCELL_UNFORCE) { + ret = INCELL_ALREADY_LOCKED; + pr_err("%s: Already power locked ret=%d\n", + __func__, ret); + return ret; + } + } + + if (incell->worker_state != INCELL_WORKER_OFF) { + ret = INCELL_EBUSY; + pr_err("%s: worker scheduling ret=%d\n", __func__, ret); + return ret; + } + + if (incell->incell_intf_operation == INCELL_TOUCH_RUN) { + ret = INCELL_EBUSY; + pr_err("%s: touch I/F not finished ret=%d\n", __func__, ret); + return ret; + } + + incell->incell_intf_operation = INCELL_TOUCH_RUN; + + if (!mutex_trylock(&info->lock)) { + incell->incell_intf_operation = INCELL_TOUCH_IDLE; + pr_err("%s: mutex_locked ret=%d\n", __func__, ret); + ret = INCELL_EBUSY; + return ret; + } + + incell->intf_mode = mode; + + switch (mode) { + case INCELL_DISPLAY_ON: + incell->intf_mode = INCELL_DISPLAY_HW_RESET; + case INCELL_DISPLAY_HW_RESET: + spec_mfd->off_sts = true; + ret = incell_display_hw_reset(incell, info); + spec_mfd->off_sts = false; + break; + case INCELL_DISPLAY_OFF: + spec_mfd->off_sts = true; + ret = incell_display_off(incell, info); + break; + default: + pr_err("%s: Invalid mode for touch interface %d\n", + __func__, (int)(mode)); + break; + } + + mutex_unlock(&info->lock); + incell->incell_intf_operation = INCELL_TOUCH_IDLE; + pr_notice("%s: FINISH - incell.status:0x%x\n", __func__, + (incell->state)); + return ret; +} + +static void incell_panel_power_worker(struct work_struct *work) +{ + struct incell_ctrl *incell = incell_get_info(); + struct fb_info *info = registered_fb[0]; + + pr_notice("%s: START - incell.status:0x%x\n", __func__, + (incell->state)); + + if (!incell) { + pr_err("%s: Invalid incell data\n", __func__); + return; + } + + if (!info) { + pr_err("%s: Invalid fb data\n", __func__); + return; + } + + mutex_lock(&info->lock); + incell->worker_state = INCELL_WORKER_ON; + + if (incell->state == INCELL_WORK_NEED_P_OFF) + incell_driver_power_off(info); + else if (incell->state == INCELL_WORK_NEED_P_ON + || incell->state == INCELL_WORK_NEED_P_ON_EWU) + incell_driver_power_on(info); + + incell->worker_state = INCELL_WORKER_OFF; + mutex_unlock(&info->lock); + + pr_notice("%s: FINISH - incell.status:0x%x\n", __func__, + (incell->state)); +} + +static void incell_panel_power_worker_scheduling(incell_pw_lock lock, + struct incell_ctrl *incell) +{ + unsigned char state = incell->state; + + if (lock == INCELL_DISPLAY_POWER_LOCK) + return; + + if (state != INCELL_WORK_NEED_P_OFF + && state != INCELL_WORK_NEED_P_ON + && state != INCELL_WORK_NEED_P_ON_EWU) + return; + + incell->worker_state = INCELL_WORKER_PENDING; + schedule_work(&incell->incell_work); + + pr_notice("%s: incell worker scheduled - incell.status:0x%x\n", + __func__, (incell->state)); +} + +void incell_panel_power_worker_canceling(struct incell_ctrl *incell) +{ + struct fb_info *info = registered_fb[0]; + struct msm_fb_data_type *mfd = NULL; + struct fb_specific_data *spec_mfd = NULL; + + cancel_work_sync(&incell->incell_work); + + pr_notice("%s: incell worker canceled - incell.status:0x%x\n", __func__, + (incell->state)); + + if (!info) { + pr_err("%s: Invalid fb data\n", __func__); + goto end; + } + + mfd = (struct msm_fb_data_type *)info->par; + if (!mfd) { + pr_err("%s: Invalid msm data\n", __func__); + goto end; + } + + spec_mfd = &mfd->spec_mfd; + if (spec_mfd->off_sts) + spec_mfd->off_sts = false; + +end: + incell->worker_state = INCELL_WORKER_OFF; +} + +static int incell_power_lock(unsigned char *state) +{ + + if (mdss_dsi_panel_driver_is_power_lock(*state)) { + pr_err("%s: Power state already locked", __func__); + return INCELL_ALREADY_LOCKED; + } + *state |= INCELL_LOCK_STATE_ON; + + return INCELL_OK; +} +static int incell_power_unlock(unsigned char *state) +{ + + if (!mdss_dsi_panel_driver_is_power_lock(*state)) { + pr_err("%s: Power state already unlocked", __func__); + return INCELL_ALREADY_UNLOCKED; + } + *state &= INCELL_LOCK_STATE_OFF; + + return INCELL_OK; +} + +int incell_power_lock_ctrl(incell_pw_lock lock, + incell_pw_status *power_status) +{ + int ret = INCELL_ERROR; + struct incell_ctrl *incell = incell_get_info(); + + if (!incell) { + pr_err("%s: Invalid incell data\n", __func__); + return ret; + } + + if (incell->worker_state != INCELL_WORKER_OFF) { + ret = INCELL_EBUSY; + pr_err("%s: worker scheduling ret=%d\n", __func__, ret); + return ret; + } + + if (incell->incell_intf_operation == INCELL_TOUCH_RUN) { + ret = INCELL_EBUSY; + pr_err("%s: touch I/F not finished ret=%d\n", __func__, ret); + return ret; + } + + incell->incell_intf_operation = INCELL_TOUCH_RUN; + + pr_debug("%s: status:0x%x --->\n", __func__, (incell->state)); + + mdss_dsi_panel_driver_update_incell_bk(incell); + + if (lock == INCELL_DISPLAY_POWER_LOCK) + ret = incell_power_lock(&(incell->state)); + else + ret = incell_power_unlock(&(incell->state)); + + pr_debug("%s: ---> status:0x%x\n", __func__, (incell->state)); + + incell_get_power_status(power_status); + incell_panel_power_worker_scheduling(lock, incell); + + incell->incell_intf_operation = INCELL_TOUCH_IDLE; + + return ret; +} + + +void incell_ewu_mode_ctrl(incell_ewu_mode ewu) +{ + struct incell_ctrl *incell = incell_get_info(); + + pr_notice("%s: START - %s\n", __func__, + ((ewu == INCELL_DISPLAY_EWU_DISABLE) ? + "INCELL_DISPLAY_EWU_DISABLE" : "INCELL_DISPLAY_EWU_ENABLE")); + + if (!incell) { + pr_err("%s: Invalid incell data\n", __func__); + return; + } + + pr_debug("%s: EWU mode is %s\n", __func__, + ewu == INCELL_DISPLAY_EWU_ENABLE ? "on":"off"); + + pr_debug("%s: status:0x%x --->\n", __func__, (incell->state)); + + mdss_dsi_panel_driver_update_incell_bk(incell); + + if (ewu == INCELL_DISPLAY_EWU_ENABLE) + incell->state |= INCELL_EWU_STATE_ON; + else + incell->state &= INCELL_EWU_STATE_OFF; + + pr_notice("%s: FINISH - incell.status:0x%x\n", __func__, + (incell->state)); +} + +void incell_driver_init(void) +{ + memset(&incell_buf, 0, sizeof(struct incell_ctrl)); + incell = &incell_buf; + + incell->state = INCELL_INIT_STATE_KERNEL; + incell->incell_intf_operation = INCELL_TOUCH_IDLE; + incell->worker_state = INCELL_WORKER_OFF; + + INIT_WORK(&incell->incell_work, incell_panel_power_worker); +} + diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 5548f0f09f8a19e14a775509c4dd10403e5331c0..221426f9f9369da2b51e0beb38d45043941fd61d 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef MDSS_H #define MDSS_H @@ -37,6 +42,10 @@ #define MDSS_PINCTRL_STATE_DEFAULT "mdss_default" #define MDSS_PINCTRL_STATE_SLEEP "mdss_sleep" +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +#define MDSS_PINCTRL_STATE_TOUCH_ACTIVE "mdss_touch_active" +#define MDSS_PINCTRL_STATE_TOUCH_SUSPEND "mdss_touch_suspend" +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ enum mdss_mdp_clk_type { MDSS_CLK_AHB, @@ -547,7 +556,6 @@ struct mdss_data_type { u32 sec_session_cnt; wait_queue_head_t secure_waitq; struct cx_ipeak_client *mdss_cx_ipeak; - struct mult_factor bus_throughput_factor; }; extern struct mdss_data_type *mdss_res; diff --git a/drivers/video/fbdev/msm/mdss_cec_core.c b/drivers/video/fbdev/msm/mdss_cec_core.c index 1d9950494d652cc02c88a317a5e4464ea8e27170..4b53b01be709d987379c5a9ededdd5c7895a39b2 100644 --- a/drivers/video/fbdev/msm/mdss_cec_core.c +++ b/drivers/video/fbdev/msm/mdss_cec_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 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 @@ -681,7 +681,7 @@ static ssize_t cec_wta_msg(struct device *dev, } spin_unlock_irqrestore(&ctl->lock, flags); - if (msg->frame_size > MAX_CEC_FRAME_SIZE) { + if (msg->frame_size > MAX_OPERAND_SIZE) { pr_err("msg frame too big!\n"); ret = -EINVAL; goto end; diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c index 3330f8f62b780c553540f289baeb6c29a1e4d783..c6ff92ed1686d91e30d88c3f85ff23c06f019200 100644 --- a/drivers/video/fbdev/msm/mdss_dba_utils.c +++ b/drivers/video/fbdev/msm/mdss_dba_utils.c @@ -576,7 +576,6 @@ int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo) video_cfg.h_pulse_width = pinfo->lcdc.h_pulse_width; video_cfg.v_pulse_width = pinfo->lcdc.v_pulse_width; video_cfg.pclk_khz = (unsigned long)pinfo->clk_rate / 1000; - video_cfg.hdmi_mode = !hdmi_edid_is_dvi_mode(ud->edid_data); /* Calculate number of DSI lanes configured */ video_cfg.num_of_input_lanes = 0; @@ -592,6 +591,8 @@ int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo) /* Get scan information from EDID */ video_cfg.vic = mdss_dba_get_vic_panel_info(ud, pinfo); ud->current_vic = video_cfg.vic; + video_cfg.hdmi_mode = hdmi_edid_get_sink_mode(ud->edid_data, + video_cfg.vic); video_cfg.scaninfo = hdmi_edid_get_sink_scaninfo(ud->edid_data, video_cfg.vic); if (ud->ops.video_on) diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 4c6a5e73406bc0361e9ccbc82ed44a6b08fadc99..2f169074261aec013e4ba3e46983e45b4917edf3 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -1094,14 +1094,8 @@ static int dp_audio_info_setup(struct platform_device *pdev, struct mdss_dp_drv_pdata *dp_ctrl = platform_get_drvdata(pdev); if (!dp_ctrl || !params) { - pr_err("invalid input\n"); - rc = -ENODEV; - goto end; - } - - if (!dp_ctrl->power_on) { - pr_debug("DP is already power off\n"); - goto end; + DEV_ERR("%s: invalid input\n", __func__); + return -ENODEV; } mdss_dp_audio_setup_sdps(&dp_ctrl->ctrl_io, params->num_of_channels); @@ -1109,7 +1103,6 @@ static int dp_audio_info_setup(struct platform_device *pdev, mdss_dp_set_safe_to_exit_level(&dp_ctrl->ctrl_io, dp_ctrl->lane_cnt); mdss_dp_audio_enable(&dp_ctrl->ctrl_io, true); -end: return rc; } /* dp_audio_info_setup */ @@ -1141,11 +1134,6 @@ static void dp_audio_teardown_done(struct platform_device *pdev) return; } - if (!dp->power_on) { - pr_err("DP is already power off\n"); - return; - } - mdss_dp_audio_enable(&dp->ctrl_io, false); /* Make sure the DP audio engine is disabled */ wmb(); @@ -1637,7 +1625,6 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) dp_drv->link_rate = mdss_dp_gen_link_clk(dp_drv); if (!dp_drv->link_rate) { pr_err("Unable to configure required link rate\n"); - mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false); ret = -EINVAL; goto exit; } @@ -2116,12 +2103,6 @@ static int mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, if (dp->hpd_notification_status == NOTIFY_UNKNOWN) goto invalid_request; if (dp->hpd_notification_status == NOTIFY_DISCONNECT_IRQ_HPD) { - /* - * Just in case if NOTIFY_DISCONNECT_IRQ_HPD is timedout - */ - if (dp->power_on) - mdss_dp_state_ctrl(&dp->ctrl_io, ST_PUSH_IDLE); - /* * user modules already turned off. Need to explicitly * turn off DP core here. @@ -3003,12 +2984,6 @@ static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata) /* wait until link training is completed */ mutex_lock(&dp_drv->train_mutex); - if (!dp_drv->power_on) { - pr_err("DP Controller not powered on\n"); - mutex_unlock(&dp_drv->train_mutex); - return; - } - reinit_completion(&dp_drv->idle_comp); mdss_dp_state_ctrl(&dp_drv->ctrl_io, ST_PUSH_IDLE); if (!wait_for_completion_timeout(&dp_drv->idle_comp, @@ -4007,6 +3982,12 @@ static int mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp) { int ret = 0; + /* In case of HPD_IRQ events without DP link being turned on such as + * adb shell stop, skip handling hpd_irq event. + */ + if (!dp->dp_initialized) + goto exit; + pr_debug("start\n"); dp->hpd_irq_on = true; @@ -4122,15 +4103,6 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv) if (dp_drv->alt_mode.dp_status.hpd_irq) { pr_debug("Attention: hpd_irq high\n"); - /* In case of HPD_IRQ events without DP link being - * turned on such as adb shell stop, skip handling - * hpd_irq event. - */ - if (!dp_drv->dp_initialized) { - pr_err("DP not initialized yet\n"); - return; - } - if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->cp_irq) { if (!dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data)) return; diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index c0632e8241a049e67fde1764b5bcdae3342e8b50..23a63121b78c0476c9154ba893bf0cde038c174a 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -395,7 +395,6 @@ static int dp_aux_rw_cmds_retry(struct mdss_dp_drv_pdata *dp, int i; u32 aux_cfg1_config_count; int ret; - bool connected = false; aux_cfg1_config_count = mdss_dp_phy_aux_get_config_cnt(dp, PHY_AUX_CFG1); @@ -405,15 +404,6 @@ retry: do { struct edp_cmd cmd1 = *cmd; - mutex_lock(&dp->attention_lock); - connected = dp->cable_connected; - mutex_unlock(&dp->attention_lock); - - if (!connected) { - pr_err("dp cable disconnected\n"); - break; - } - dp->aux_error_num = EDP_AUX_ERR_NONE; pr_debug("Trying %s, iteration count: %d\n", mdss_dp_aux_transaction_to_string(transaction), @@ -684,11 +674,6 @@ char mdss_dp_gen_link_clk(struct mdss_dp_drv_pdata *dp) pr_debug("clk_rate=%llu, bpp= %d, lane_cnt=%d\n", pinfo->clk_rate, pinfo->bpp, lane_cnt); - if (lane_cnt == 0) { - pr_warn("Invalid max lane count\n"); - return 0; - } - /* * The max pixel clock supported is 675Mhz. The * current calculations below will make sure diff --git a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c index 36a062dc5207189914207c56f4504a0af4470e94..5a677dfe7484851ef4e5fbbd7739aa6a011b6619 100644 --- a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c @@ -894,24 +894,22 @@ static bool dp_hdcp2p2_supported(struct dp_hdcp2p2_ctrl *ctrl) { struct edp_cmd cmd = {0}; const u32 offset = 0x6921d; - u8 buf[3]; + u8 buf; cmd.read = 1; cmd.addr = offset; - cmd.len = ARRAY_SIZE(buf); - cmd.out_buf = buf; + cmd.len = sizeof(buf); + cmd.out_buf = &buf; if (dp_aux_read(ctrl->init_data.cb_data, &cmd)) { pr_err("RxCaps read failed\n"); goto error; } - pr_debug("HDCP_CAPABLE=%lu\n", (buf[2] & BIT(1)) >> 1); - pr_debug("VERSION=%d\n", buf[0]); + pr_debug("rxcaps 0x%x\n", buf); - if ((buf[2] & BIT(1)) && (buf[0] == 0x2)) + if (buf & BIT(1)) return true; - error: return false; } diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 7b6153503af5be47567b06bece82a43cd09dddde..81a4b1b4074afb983eaf09ddf812bf6d0de1f426 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -34,6 +39,9 @@ #include "mdss_debug.h" #include "mdss_dsi_phy.h" #include "mdss_dba_utils.h" +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +#include "mdss_dsi_panel_driver.h" +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ #define CMDLINE_DSI_CTL_NUM_STRING_LEN 2 @@ -185,8 +193,10 @@ static void mdss_dsi_pm_qos_update_request(int val) pm_qos_update_request(&mdss_dsi_pm_qos_request, val); } +#ifndef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL static int mdss_dsi_pinctrl_set_state(struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool active); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl(u32 ctrl_id) { @@ -365,6 +375,9 @@ static int mdss_dsi_regulator_init(struct platform_device *pdev, static int mdss_dsi_panel_power_off(struct mdss_panel_data *pdata) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + return mdss_dsi_panel_driver_power_off(pdata); +#else int ret = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; @@ -395,10 +408,14 @@ static int mdss_dsi_panel_power_off(struct mdss_panel_data *pdata) end: return ret; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + return mdss_dsi_panel_driver_power_on(pdata); +#else int ret = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; @@ -437,6 +454,7 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata) } return ret; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } static int mdss_dsi_panel_power_lp(struct mdss_panel_data *pdata, int enable) @@ -968,7 +986,7 @@ static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id) while (len >= sizeof(*dchdr)) { dchdr = (struct dsi_ctrl_hdr *)bp; dchdr->dlen = ntohs(dchdr->dlen); - if (dchdr->dlen > len || dchdr->dlen < 0) { + if (dchdr->dlen > len) { pr_err("%s: dtsi cmd=%x error, len=%d\n", __func__, dchdr->dtype, dchdr->dlen); kfree(buf); @@ -1479,6 +1497,9 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) struct mipi_panel_info *mipi; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; int cur_power_state; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct incell_ctrl *incell = incell_get_info(); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); @@ -1561,9 +1582,14 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) * data lanes for LP11 init */ if (mipi->lp11_init) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if ((!incell) || (incell->seq == POWER_ON_EXECUTE)) + mdss_dsi_panel_driver_reset_dual_display(ctrl_pdata); +#else if (mdss_dsi_pinctrl_set_state(ctrl_pdata, true)) pr_debug("reset enable: pinctrl not enabled\n"); mdss_dsi_panel_reset(pdata, 1); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } if (mipi->init_delay) @@ -1578,9 +1604,15 @@ end: return ret; } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +int mdss_dsi_pinctrl_set_state( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, + bool active) +#else static int mdss_dsi_pinctrl_set_state( struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool active) +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ { struct pinctrl_state *pin_state; struct mdss_panel_info *pinfo = NULL; @@ -1638,7 +1670,11 @@ static int mdss_dsi_pinctrl_init(struct platform_device *pdev) if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.gpio_state_suspend)) pr_warn("%s: can not get sleep pinstate\n", __func__); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + return mdss_dsi_panel_driver_pinctrl_init(ctrl_pdata); +#else return 0; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } static int mdss_dsi_unblank(struct mdss_panel_data *pdata) @@ -1703,6 +1739,10 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_unblank(ctrl_pdata); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + error: mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle, MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_OFF); @@ -2720,6 +2760,8 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, ctrl_pdata->update_phy_timing); rc = mdss_dsi_on(pdata); + mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, + pdata); break; case MDSS_EVENT_UNBLANK: if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) @@ -2928,13 +2970,18 @@ static struct device_node *mdss_dsi_find_panel_of_node( char panel_name[MDSS_MAX_PANEL_LEN] = ""; char ctrl_id_stream[3] = "0:"; char *str1 = NULL, *str2 = NULL, *override_cfg = NULL; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL char cfg_np_name[MDSS_MAX_PANEL_LEN] = ""; struct device_node *dsi_pan_node = NULL, *mdss_node = NULL; +#else + struct device_node *dsi_pan_node = NULL; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev); struct mdss_panel_info *pinfo = &ctrl_pdata->panel_data.panel_info; len = strlen(panel_cfg); ctrl_pdata->panel_data.dsc_cfg_np_name[0] = '\0'; + len = 0; /* temporary */ if (!len) { /* no panel cfg chg, parse dt */ pr_debug("%s:%d: no cmd line cfg present\n", @@ -3022,12 +3069,20 @@ static struct device_node *mdss_dsi_find_panel_of_node( cfg_np_name, MDSS_MAX_PANEL_LEN); } } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_detection(pdev, &dsi_pan_node); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ return dsi_pan_node; } end: if (strcmp(panel_name, NONE_PANEL)) dsi_pan_node = mdss_dsi_pref_prim_panel(pdev); + +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_detection(pdev, &dsi_pan_node); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + exit: return dsi_pan_node; } @@ -3060,6 +3115,9 @@ static struct device_node *mdss_dsi_config_panel(struct platform_device *pdev, return NULL; } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + ctrl_pdata->panel_data.panel_pdev = pdev; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ rc = mdss_dsi_panel_init(dsi_pan_node, ctrl_pdata, ndx); if (rc) { pr_err("%s: dsi panel init failed\n", __func__); @@ -3192,6 +3250,10 @@ static int mdss_dsi_cont_splash_config(struct mdss_panel_info *pinfo, void *clk_handle; int rc = 0; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_check_splash_enable(ctrl_pdata); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + if (pinfo->cont_splash_enabled) { rc = mdss_dsi_panel_power_ctrl(&(ctrl_pdata->panel_data), MDSS_PANEL_POWER_ON); @@ -3266,6 +3328,21 @@ end: return rc; } +static void mdss_dsi_ctrl_validate_lane_swap_config( + struct mdss_dsi_ctrl_pdata *ctrl) +{ + struct mipi_panel_info *mipi = &ctrl->panel_data.panel_info.mipi; + + if (!mipi->data_lane0) + ctrl->lane_map[DSI_LOGICAL_LANE_0] = DSI_PHYSICAL_LANE_INVALID; + if (!mipi->data_lane1) + ctrl->lane_map[DSI_LOGICAL_LANE_1] = DSI_PHYSICAL_LANE_INVALID; + if (!mipi->data_lane2) + ctrl->lane_map[DSI_LOGICAL_LANE_2] = DSI_PHYSICAL_LANE_INVALID; + if (!mipi->data_lane3) + ctrl->lane_map[DSI_LOGICAL_LANE_3] = DSI_PHYSICAL_LANE_INVALID; +} + static int mdss_dsi_ctrl_validate_config(struct mdss_dsi_ctrl_pdata *ctrl) { int rc = 0; @@ -3275,6 +3352,8 @@ static int mdss_dsi_ctrl_validate_config(struct mdss_dsi_ctrl_pdata *ctrl) goto error; } + mdss_dsi_ctrl_validate_lane_swap_config(ctrl); + /* * check to make sure that the byte interface clock is specified for * DSI ctrl version 2 and above. @@ -3567,6 +3646,11 @@ static void mdss_dsi_res_deinit(struct platform_device *pdev) if (pinfo) mdss_dba_utils_deinit(pinfo->dba_data); } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + devm_kfree(&pdev->dev, + dsi_res->ctrl_pdata[i]->spec_pdata); + if (dsi_res->ctrl_pdata[i]) +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ devm_kfree(&pdev->dev, dsi_res->ctrl_pdata[i]); } @@ -3685,6 +3769,21 @@ static int mdss_dsi_res_init(struct platform_device *pdev) rc = -ENOMEM; goto mem_fail; } + +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_res->ctrl_pdata[i]->spec_pdata = devm_kzalloc( + &pdev->dev, + sizeof(struct mdss_panel_specific_pdata), + GFP_KERNEL); + + if (!mdss_dsi_res->ctrl_pdata[i]->spec_pdata) { + pr_err("%s Unable to alloc spec_pdata =%d\n", + __func__, i); + rc = -ENOMEM; + goto mem_fail; + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + pr_debug("%s Allocated ctrl_pdata[%d]=%pK\n", __func__, i, mdss_dsi_res->ctrl_pdata[i]); mdss_dsi_res->ctrl_pdata[i]->shared_data = @@ -4315,6 +4414,9 @@ static int mdss_dsi_parse_gpio_params(struct platform_device *ctrl_pdev, ctrl_pdata->lcd_mode_sel_gpio = -EINVAL; } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_parse_gpio_params(ctrl_pdev, ctrl_pdata); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ return 0; } @@ -4392,6 +4494,10 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, return rc; } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_labibb_vreg_init(ctrl_pdata); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + rc = mdss_dsi_parse_ctrl_params(ctrl_pdev, pan_node, ctrl_pdata); if (rc) { pr_err("%s: failed to parse ctrl settings, rc=%d\n", diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 9847016fed2963d88ced9aac73c1371a643f6169..fdfc346bd54229fed3ef0c7a7198461bccec35c4 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef MDSS_DSI_H #define MDSS_DSI_H @@ -375,6 +380,10 @@ struct dsi_pinctrl_res { struct pinctrl *pinctrl; struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct pinctrl_state *touch_state_active; + struct pinctrl_state *touch_state_suspend; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ }; struct panel_horizontal_idle { @@ -591,6 +600,9 @@ struct mdss_dsi_ctrl_pdata { bool update_phy_timing; /* flag to recalculate PHY timings */ bool phy_power_off; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct mdss_panel_specific_pdata *spec_pdata; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ }; struct dsi_status_data { diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index c766ff98304569dc6ce8fe480df8d7bb555d2ea9..3b928da32591e9a81da3f25e17510f0d9441673d 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -1190,12 +1195,22 @@ int mdss_dsi_reg_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { int ret = 0; struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct mipi_panel_info *mipi = NULL; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (ctrl_pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return 0; } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mipi = &ctrl_pdata->panel_data.panel_info.mipi; + if (mipi->switch_mode_pending == true) { + pr_err("%s: Skip status check, Pending switch mode\n", __func__); + return 0; + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ pr_debug("%s: Checking Register status\n", __func__); mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle, @@ -2675,6 +2690,9 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) int rc = 0; bool hs_req = false; bool cmd_mutex_acquired = false; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + bool cmdlist_mutex_acquired = false; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (from_mdp) { /* from mdp kickoff */ if (!ctrl->burst_mode_enabled) { @@ -2690,6 +2708,11 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) if (req && from_mdp && ctrl->burst_mode_enabled) { mutex_lock(&ctrl->cmd_mutex); cmd_mutex_acquired = true; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + } else if (!from_mdp) { + mutex_lock(&ctrl->cmdlist_mutex); + cmdlist_mutex_acquired = true; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid, @@ -2714,6 +2737,10 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) } else { if (cmd_mutex_acquired) mutex_unlock(&ctrl->cmd_mutex); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (cmdlist_mutex_acquired) + mutex_unlock(&ctrl->cmdlist_mutex); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ return -EPERM; } } @@ -2762,6 +2789,10 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) pr_err("%s: Bus bw vote failed\n", __func__); if (from_mdp) mutex_unlock(&ctrl->cmd_mutex); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (cmdlist_mutex_acquired) + mutex_unlock(&ctrl->cmdlist_mutex); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ return rc; } @@ -2770,6 +2801,10 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) if (IS_ERR_VALUE(rc)) { pr_err("IOMMU attach failed\n"); mutex_unlock(&ctrl->cmd_mutex); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (cmdlist_mutex_acquired) + mutex_unlock(&ctrl->cmdlist_mutex); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ return rc; } use_iommu = true; @@ -2833,6 +2868,11 @@ need_lock: ctrl->panel_mode == DSI_CMD_MODE && (req && (req->flags & CMD_REQ_HS_MODE))) mdss_dsi_cmd_stop_hs_clk_lane(ctrl); + +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (cmdlist_mutex_acquired) + mutex_unlock(&ctrl->cmdlist_mutex); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } return ret; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index dbd58f93e907af2e63fa9f3c0764db407e9a00a0..a846355239ba15b06098041d80d9d3102b57fa83 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -26,6 +31,10 @@ #include "mdss_dsi.h" #include "mdss_dba_utils.h" #include "mdss_debug.h" +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +#include "mdss_dsi_panel_driver.h" +#include "mdss_dsi_panel_debugfs.h" +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ #define DT_CMD_HDR 6 #define DEFAULT_MDP_TRANSFER_TIME 14000 @@ -180,9 +189,13 @@ static void mdss_dsi_panel_apply_settings(struct mdss_dsi_ctrl_pdata *ctrl, mdss_dsi_cmdlist_put(ctrl, &cmdreq); } - +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_panel_cmds *pcmds, u32 flags) +#else static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_panel_cmds *pcmds, u32 flags) +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL*/ { struct dcs_cmd_req cmdreq; struct mdss_panel_info *pinfo; @@ -246,10 +259,20 @@ static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level) mdss_dsi_cmdlist_put(ctrl, &cmdreq); } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +#else static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ { int rc = 0; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + rc = mdss_dsi_panel_driver_request_gpios(ctrl_pdata); + if (rc) + goto specific_panel_err; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) { rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable"); @@ -294,7 +317,13 @@ rst_gpio_err: if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) gpio_free(ctrl_pdata->disp_en_gpio); disp_en_gpio_err: +#ifndef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + return rc; +#else + mdss_dsi_panel_driver_gpio_free(ctrl_pdata); +specific_panel_err: return rc; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } int mdss_dsi_bl_gpio_ctrl(struct mdss_panel_data *pdata, int enable) @@ -374,6 +403,9 @@ ret: int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + return mdss_dsi_panel_driver_reset_panel(pdata, enable); +#else struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo = NULL; int i, rc = 0; @@ -506,6 +538,7 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) exit: return rc; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } /** @@ -829,12 +862,23 @@ static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata, pr_debug("%s: sending switch commands\n", __func__); pcmds = &pt->switch_cmds; flags |= CMD_REQ_DMA_TPG; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mipi->switch_mode_pending = true; +#else flags |= CMD_REQ_COMMIT; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } else { pr_warn("%s: Invalid mode switch attempted\n", __func__); return; } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) && + (mipi->switch_mode_pending == true)) + mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info); + + mdss_dsi_panel_cmds_send(ctrl_pdata, pcmds, flags); +#else if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) && (pdata->panel_info.send_pps_before_switch)) mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info); @@ -844,6 +888,7 @@ static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata, if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) && (!pdata->panel_info.send_pps_before_switch)) mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata, @@ -921,6 +966,9 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) struct mdss_panel_info *pinfo; struct dsi_panel_cmds *on_cmds; int ret = 0; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct mdss_panel_specific_pdata *spec_pdata = NULL; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); @@ -933,6 +981,13 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) pr_debug("%s: ndx=%d\n", __func__, ctrl->ndx); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + spec_pdata = mdss_panel2spec_pdata(pdata); + + if (spec_pdata->crash_counter_reset) + spec_pdata->crash_counter_reset(); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + if (pinfo->dcs_cmd_by_left) { if (ctrl->ndx != DSI_CTRL_LEFT) goto end; @@ -970,6 +1025,11 @@ static int mdss_dsi_post_panel_on(struct mdss_panel_data *pdata) struct mdss_panel_info *pinfo; struct dsi_panel_cmds *cmds; u32 vsync_period = 0; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct incell_ctrl *incell = incell_get_info(); + unsigned char state; + struct mdss_panel_specific_pdata *spec_pdata = NULL; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); @@ -998,6 +1058,21 @@ static int mdss_dsi_post_panel_on(struct mdss_panel_data *pdata) mdss_dba_utils_hdcp_enable(pinfo->dba_data, true); } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + spec_pdata = mdss_panel2spec_pdata(pdata); + if (incell && (spec_pdata->panel_type == HYBRID_INCELL)) { + state = incell->state; + if ((!mdss_dsi_panel_driver_is_power_on(state)) && + (!mdss_dsi_panel_driver_is_ewu(state))) + mdss_dsi_panel_driver_reset_touch(pdata, 0); + } + mdss_dsi_panel_driver_reset_touch(pdata, 1); + + if (incell) + mdss_dsi_panel_driver_state_change_on(incell); + mdss_dsi_panel_driver_post_on(ctrl); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + end: pr_debug("%s:-\n", __func__); return 0; @@ -1007,6 +1082,14 @@ static int mdss_dsi_panel_off(struct mdss_panel_data *pdata) { struct mdss_dsi_ctrl_pdata *ctrl = NULL; struct mdss_panel_info *pinfo; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct incell_ctrl *incell = incell_get_info(); + + if (incell) { + mdss_dsi_panel_driver_power_off_ctrl(incell); + mdss_dsi_panel_driver_state_change_off(incell); + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); @@ -1033,6 +1116,10 @@ static int mdss_dsi_panel_off(struct mdss_panel_data *pdata) } end: +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (pdata->panel_info.dsi_master == pdata->panel_info.pdest) + mdss_dsi_panel_driver_off(ctrl); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ pr_debug("%s:-\n", __func__); return 0; } @@ -1122,9 +1209,13 @@ static void mdss_dsi_parse_trigger(struct device_node *np, char *trigger, } } - +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +int mdss_dsi_parse_dcs_cmds(struct device_node *np, + struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key) +#else static int mdss_dsi_parse_dcs_cmds(struct device_node *np, struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key) +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ { const char *data; int blen = 0, len; @@ -2587,8 +2678,10 @@ static int mdss_dsi_panel_timing_from_dt(struct device_node *np, if (np->name) { pt->timing.name = kstrdup(np->name, GFP_KERNEL); +#ifndef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL pr_info("%s: found new timing \"%s\" (%pK)\n", __func__, np->name, &pt->timing); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } return 0; @@ -2709,6 +2802,9 @@ static int mdss_panel_parse_dt(struct device_node *np, { u32 tmp; int rc, len = 0; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + int i; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ const char *data; static const char *pdest; const char *bridge_chip_name; @@ -2750,6 +2846,21 @@ static int mdss_panel_parse_dt(struct device_node *np, pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; } + +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (pinfo->pdest == DISPLAY_1) { + if (of_property_read_bool(np, "somc,mdss-dsi-master")) + pinfo->dsi_master = DISPLAY_1; + else + pinfo->dsi_master = DISPLAY_2; + } else { + if (of_property_read_bool(np, "somc,mdss-dsi-master")) + pinfo->dsi_master = DISPLAY_2; + else + pinfo->dsi_master = DISPLAY_1; + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + pdest = of_get_property(np, "qcom,mdss-dsi-panel-destination", NULL); @@ -2904,6 +3015,28 @@ static int mdss_panel_parse_dt(struct device_node *np, rc = of_property_read_u32(np, "qcom,mdss-dsi-post-init-delay", &tmp); pinfo->mipi.post_init_delay = (!rc ? tmp : 0); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + data = of_get_property(np, + "somc,platform-regulator-settings", &len); + if (!data || len != 7) { + pr_debug("%s:%d, Unable to read Phy regulator settings", + __func__, __LINE__); + } else { + for (i = 0; i < len; i++) + pinfo->mipi.dsi_phy_db.regulator[i] = data[i]; + } + + data = of_get_property(np, + "somc,mdss-dsi-lane-config", &len); + if (!data || len != 45) { + pr_debug("%s:%d, Unable to read Phy lane configure settings", + __func__, __LINE__); + } else { + for (i = 0; i < len; i++) + pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i]; + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + mdss_dsi_parse_trigger(np, &(pinfo->mipi.mdp_trigger), "qcom,mdss-dsi-mdp-trigger"); @@ -2922,6 +3055,14 @@ static int mdss_panel_parse_dt(struct device_node *np, pinfo->mipi.force_clk_lane_hs = of_property_read_bool(np, "qcom,mdss-dsi-force-clock-lane-hs"); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + rc = mdss_dsi_panel_driver_parse_dt(np, ctrl_pdata); + if (rc) { + pr_err("%s: failed to parse somc features\n", __func__); + goto error; + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + rc = mdss_dsi_parse_panel_features(np, ctrl_pdata); if (rc) { pr_err("%s: failed to parse panel features\n", __func__); @@ -2970,6 +3111,10 @@ int mdss_dsi_panel_init(struct device_node *node, int rc = 0; static const char *panel_name; struct mdss_panel_info *pinfo; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct platform_device *pdev; + u32 index; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (!node || !ctrl_pdata) { pr_err("%s: Invalid arguments\n", __func__); @@ -2978,6 +3123,26 @@ int mdss_dsi_panel_init(struct device_node *node, pinfo = &ctrl_pdata->panel_data.panel_info; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + pdev = ctrl_pdata->panel_data.panel_pdev; + + rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index); + if (rc) { + dev_err(&pdev->dev, + "%s: Cell-index not specified, rc=%d\n", + __func__, rc); + return rc; + } + + if (!index) { + rc = mdss_dsi_panel_create_fs(ctrl_pdata); + if (rc) { + pr_err("%s: mdss_dsi_panel_create_fs rc = %d\n", __func__, rc); + return rc; + } + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + pr_debug("%s:%d\n", __func__, __LINE__); pinfo->panel_name[0] = '\0'; panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", NULL); @@ -2985,6 +3150,9 @@ int mdss_dsi_panel_init(struct device_node *node, pr_info("%s:%d, Panel name not specified\n", __func__, __LINE__); } else { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + pinfo->panel_id_name = panel_name; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ pr_info("%s: Panel Name = %s\n", __func__, panel_name); strlcpy(&pinfo->panel_name[0], panel_name, MDSS_MAX_PANEL_LEN); } @@ -3007,6 +3175,9 @@ int mdss_dsi_panel_init(struct device_node *node, ctrl_pdata->panel_data.apply_display_setting = mdss_dsi_panel_apply_display_setting; ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode; - +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_init(ctrl_pdata); + pinfo->mipi.switch_mode_pending = false; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ return 0; } diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel_debugfs.c b/drivers/video/fbdev/msm/mdss_dsi_panel_debugfs.c new file mode 100644 index 0000000000000000000000000000000000000000..99ec84d4df4849feb070b56ceae06ae8e97bb932 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_dsi_panel_debugfs.c @@ -0,0 +1,1456 @@ +/* + * drivers/video/fbdev/msm/mdss_dsi_panel_debugfs.c + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mdss_fb.h" +#include "mdss_mdp.h" +#include "mdss_dsi.h" +#include "mdss_dsi_panel_driver.h" +#include "mdss_dsi_panel_debugfs.h" + +struct device virtdev; +struct device incelldev; + +static char *res_buf; +static int buf_sz; + +static struct dsi_buf debug_tx_buf; +static struct dsi_buf debug_rx_buf; + +static struct blackscreen_det bs_det; +static struct first_frame_flushed_det fff_det; + +#define DSI_BUF_SIZE 1024 +#define TMP_BUF_SZ 128 +#define MAX_WRITE_DATA 100 + +#define DEFAULT_BS_THRESHOLD 500 + +enum dbg_cmd_type { + DCS, + GEN, +}; + +static void update_res_buf(char *string) +{ + res_buf = krealloc(res_buf, buf_sz + strnlen(string, TMP_BUF_SZ) + 1, + GFP_KERNEL); + if (!res_buf) { + pr_err("%s: Failed to allocate buffer\n", __func__); + return; + } + + memcpy(res_buf + buf_sz, string, strnlen(string, TMP_BUF_SZ) + 1); + buf_sz += strnlen(string, TMP_BUF_SZ); /* Exclude NULL termination */ +} + +static void reset_res_buf(void) +{ + kzfree(res_buf); + res_buf = NULL; + buf_sz = 0; +} + +static void print_params(int dtype, u8 reg, int len, u8 *data) +{ + int i = 0; + char tmp[TMP_BUF_SZ]; + + switch (dtype) { + case DTYPE_GEN_WRITE: + update_res_buf("GEN_WRITE\n"); + break; + case DTYPE_GEN_WRITE1: + update_res_buf("GEN_WRITE1\n"); + break; + case DTYPE_GEN_WRITE2: + update_res_buf("GEN_WRITE2\n"); + break; + case DTYPE_GEN_LWRITE: + update_res_buf("GEN_LWRITE\n"); + break; + case DTYPE_GEN_READ: + update_res_buf("GEN_READ\n"); + break; + case DTYPE_GEN_READ1: + update_res_buf("GEN_READ1\n"); + break; + case DTYPE_GEN_READ2: + update_res_buf("GEN_READ2\n"); + break; + case DTYPE_DCS_LWRITE: + update_res_buf("DCS_LWRITE\n"); + break; + case DTYPE_DCS_WRITE: + update_res_buf("DCS_WRITE\n"); + break; + case DTYPE_DCS_WRITE1: + update_res_buf("DCS_WRITE1\n"); + break; + case DTYPE_DCS_READ: + update_res_buf("DCS_READ\n"); + break; + default: + snprintf(tmp, sizeof(tmp), "Unknown dtype = 0x%x\n", dtype); + update_res_buf(tmp); + } + + if (len > 0) { + snprintf(tmp, sizeof(tmp), "reg=0x%.2X\n", reg); + update_res_buf(tmp); + snprintf(tmp, sizeof(tmp), "len=%d\n", len); + update_res_buf(tmp); + for (i = 0; i < len; i++) { + snprintf(tmp, sizeof(tmp), "data[%d]=0x%.2X\n", i, + data[i]); + update_res_buf(tmp); + } + } else { + update_res_buf("Something went wrong, length is zero.\n"); + snprintf(tmp, sizeof(tmp), + "reg=0x%.2X, len=%d, data[0]=0x%.2X\n", + reg, len, data[0]); + update_res_buf(tmp); + } +} + +static int setup_reg_access(char **buf, const char __user *ubuf, size_t count) +{ + int ret = 0; + + reset_res_buf(); + + *buf = kzalloc(sizeof(char) * count, GFP_KERNEL); + if (!*buf) { + pr_err("%s: Failed to allocate buffer\n", __func__); + ret = -ENOMEM; + goto exit; + } + + if (copy_from_user(*buf, ubuf, count)) { + ret = -EFAULT; + goto exit; + } + return 0; + +exit: + kzfree(*buf); + return ret; +} + +static int get_cmd_type(char *buf, enum dbg_cmd_type *cmd) +{ + int ret = 0; + + if (!strncmp(buf, "dcs", 3)) + *cmd = DCS; + else if (!strncmp(buf, "gen", 3)) + *cmd = GEN; + else + ret = -EFAULT; + return ret; +} + +static int get_parameters(const char *p, u8 *par_buf, int par_buf_size, + int *nbr_params) +{ + int ret = 0; + + while (true) { + if (isspace(*p)) { + p++; + } else { + if (sscanf(p, "%4hhx", &par_buf[*nbr_params]) == 1) { + (*nbr_params)++; + while (isxdigit(*p) || (*p == 'x')) + p++; + } + } + if (*nbr_params > par_buf_size) { + update_res_buf("Too many parameters\n"); + ret = -EINVAL; + goto exit; + } + if (iscntrl(*p)) + break; + } +exit: + return ret; +} + +static u32 panel_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_cmd_desc *cmds, void (*fxn)(int), + char *rbuf, int len) +{ + struct dcs_cmd_req cmdreq; + struct mdss_panel_info *pinfo; + + pinfo = &(ctrl->panel_data.panel_info); + + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds = cmds; + cmdreq.cmds_cnt = 1; + cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT; + cmdreq.rlen = len; + cmdreq.rbuf = rbuf; + cmdreq.cb = fxn; /* call back */ + + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); + mdss_dsi_cmdlist_put(ctrl, &cmdreq); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); + /* + * blocked here, until call back called + */ + + return 0; +} + +static void panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_cmd_desc *cmds, int cmd_cnt, + int link_state) +{ + struct dcs_cmd_req cmdreq; + struct mdss_panel_info *pinfo; + + pinfo = &(ctrl->panel_data.panel_info); + + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds = cmds; + cmdreq.cmds_cnt = cmd_cnt; + cmdreq.flags = CMD_REQ_COMMIT; + + /* Panel ON/Off commands should be sent in DSI Low Power Mode */ + if (link_state == DSI_LP_MODE) + cmdreq.flags |= CMD_REQ_LP_MODE; + + cmdreq.rlen = 0; + cmdreq.cb = NULL; + + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); + mdss_dsi_cmdlist_put(ctrl, &cmdreq); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); +} + +static ssize_t reg_read(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct msm_fb_data_type *mfd = s->private; + struct mdss_panel_data *pdata; + struct mdss_mdp_ctl *ctl; + u8 params[3]; /* No more than reg + two parameters is allowed */ + char *buf, *rbuf; + const char *p; + int ret; + int nbr_bytes_to_read; + int i; + int j; + enum dbg_cmd_type cmd; + struct dsi_cmd_desc dsi; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + if (!mfd->panel_power_state) { + pr_err("%s: panel is NOT on\n", __func__); + goto exit; + } + + ctl = mfd_to_ctl(mfd); + if (!ctl) + goto exit; + + if (mutex_lock_interruptible(&ctl->lock)) + goto exit; + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("%s: no panel connected\n", __func__); + goto exit; + } + + ctrl_pdata = mdss_dsi_get_master_ctrl(pdata); + if (!ctrl_pdata) { + pr_err("%s: Invalid input data\n", __func__); + goto exit; + } + + pr_err("%s\n", __func__); + + ret = setup_reg_access(&buf, ubuf, count); + if (ret) + goto exit; + + ret = get_cmd_type(buf, &cmd); + if (ret) { + update_res_buf("Read - unknown type\n"); + goto fail_free_buf; + } + + p = buf; + p = p+4; + + /* Get nbr_bytes_to_read */ + if (sscanf(p, "%d", &nbr_bytes_to_read) != 1) { + update_res_buf("Read - parameter error\n"); + goto fail_free_buf; + } + + while (isxdigit(*p) || (*p == 'x')) + p++; + + pr_err("%s: nbr_bytes_to_read = %d\n", __func__, nbr_bytes_to_read); + i = 0; + + ret = get_parameters(p, params, ARRAY_SIZE(params), &i); + if (ret) + goto fail_free_buf; + + if (cmd == DCS) { + dsi.dchdr.dtype = DTYPE_DCS_READ; + } else { + if (i == 1) { /* 0 parameters */ + dsi.dchdr.dtype = DTYPE_GEN_READ; + } else if (i == 2) { /* 1 parameter */ + dsi.dchdr.dtype = DTYPE_GEN_READ1; + } else { /* 2 paramters */ + dsi.dchdr.dtype = DTYPE_GEN_READ2; + } + } + dsi.dchdr.last = 1; + dsi.dchdr.vc = 0; + dsi.dchdr.ack = 1; + dsi.dchdr.wait = 5; + dsi.dchdr.dlen = i; + dsi.payload = params; + + pr_err("%s: dtype=%d, last=%d, vc=%d, ack=%d, wait=%d, dlen=%d\n", + __func__, + dsi.dchdr.dtype, dsi.dchdr.last, dsi.dchdr.vc, dsi.dchdr.ack, + dsi.dchdr.wait, dsi.dchdr.dlen); + for (j = 0; j < i; j++) + pr_err("%s: payload[%d] = 0x%x\n", + __func__, j, dsi.payload[j]); + + rbuf = kzalloc(sizeof(char) * nbr_bytes_to_read, GFP_KERNEL); + if (!rbuf) { + pr_err("%s: Failed to allocate buffer\n", __func__); + goto fail_free_buf; + } + + panel_cmd_read(ctrl_pdata, &dsi, NULL, rbuf, nbr_bytes_to_read); + + mutex_unlock(&ctl->lock); + + print_params(dsi.dchdr.dtype, params[0], nbr_bytes_to_read, + rbuf); + + if (rbuf) + kzfree(rbuf); +fail_free_buf: + if (buf) + kzfree(buf); +exit: + return count; +} + +static ssize_t reg_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct msm_fb_data_type *mfd = s->private; + struct mdss_panel_data *pdata; + struct mdss_mdp_ctl *ctl; + char *buf; + const char *p; + enum dbg_cmd_type cmd; + u8 data[MAX_WRITE_DATA]; + int i = 0; + int j; + int ret; + struct dsi_cmd_desc dsi; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + if (!mfd->panel_power_state) { + pr_err("%s: panel is NOT on\n", __func__); + goto exit; + } + + ctl = mfd_to_ctl(mfd); + if (!ctl) + goto exit; + + if (mutex_lock_interruptible(&ctl->lock)) + goto exit; + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("%s: no panel connected\n", __func__); + goto exit; + } + + ctrl_pdata = mdss_dsi_get_master_ctrl(pdata); + if (!ctrl_pdata) { + pr_err("%s: Invalid input data\n", __func__); + goto exit; + } + + pr_err("%s\n", __func__); + ret = setup_reg_access(&buf, ubuf, count); + if (ret) + goto exit; + + ret = get_cmd_type(buf, &cmd); + if (ret) { + update_res_buf("Write - unknown type\n"); + goto fail_free_all; + } + + p = buf; + p = p+4; + + /* Get first param, Register */ + if (sscanf(p, "%4hhx", &data[0]) != 1) { + update_res_buf("Write - parameter error\n"); + goto fail_free_all; + } + i++; + + while (isxdigit(*p) || (*p == 'x')) + p++; + + ret = get_parameters(p, data, ARRAY_SIZE(data) - 1, &i); + if (ret) + goto fail_free_all; + + if (cmd == DCS) { + if (i == 1) { /* 0 parameters */ + dsi.dchdr.dtype = DTYPE_DCS_WRITE; + } else if (i == 2) { /* 1 parameter */ + dsi.dchdr.dtype = DTYPE_DCS_WRITE1; + } else { /* Many parameters */ + dsi.dchdr.dtype = DTYPE_DCS_LWRITE; + } + } else { + if (i == 1) { /* 0 parameters */ + dsi.dchdr.dtype = DTYPE_GEN_WRITE; + } else if (i == 2) { /* 1 parameter */ + dsi.dchdr.dtype = DTYPE_GEN_WRITE1; + } else if (i == 3) { /* 2 parameters */ + dsi.dchdr.dtype = DTYPE_GEN_WRITE2; + } else { /* Many parameters */ + dsi.dchdr.dtype = DTYPE_GEN_LWRITE; + } + } + dsi.dchdr.last = 1; + dsi.dchdr.vc = 0; + dsi.dchdr.ack = 0; + dsi.dchdr.wait = 0; + dsi.dchdr.dlen = i; + dsi.payload = data; + + pr_err("%s: last = %d, vc = %d, ack = %d, wait = %d, dlen = %d\n", + __func__, + dsi.dchdr.last, dsi.dchdr.vc, dsi.dchdr.ack, dsi.dchdr.wait, + dsi.dchdr.dlen); + for (j = 0; j < i; j++) + pr_err("%s: payload[%d] = 0x%x\n", + __func__, j, dsi.payload[j]); + + panel_cmds_send(ctrl_pdata, &dsi, 1, DSI_LP_MODE); + + print_params(dsi.dchdr.dtype, data[0], i, dsi.payload); + + mutex_unlock(&ctl->lock); + +fail_free_all: + kzfree(buf); +exit: + return count; +} + +static int result_show(struct seq_file *s, void *unused) +{ + seq_printf(s, "%s", res_buf); + if (!res_buf) + seq_printf(s, "\n"); + return 0; +} + +static int read_open(struct inode *inode, struct file *file) +{ + return single_open(file, NULL, inode->i_private); +} + +static const struct file_operations read_fops = { + .owner = THIS_MODULE, + .open = read_open, + .write = reg_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int write_open(struct inode *inode, struct file *file) +{ + return single_open(file, NULL, inode->i_private); +} + +static const struct file_operations write_fops = { + .owner = THIS_MODULE, + .open = write_open, + .write = reg_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int result_open(struct inode *inode, struct file *file) +{ + return single_open(file, result_show, inode->i_private); +} + +static const struct file_operations result_fops = { + .owner = THIS_MODULE, + .open = result_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static ssize_t incell_panel_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + incell_pw_status power_status; + bool display = false; + bool touch = false; + + power_status.touch_power = false; + power_status.display_power = false; + ret = incell_get_power_status(&power_status); + + if (ret == INCELL_OK) { + display = power_status.display_power; + touch = power_status.touch_power; + } else { + return scnprintf(buf, PAGE_SIZE, "%s\n", "Get failed"); + } + + return scnprintf(buf, PAGE_SIZE, "touch = %d, display = %d\n", + touch, display); +} + +static ssize_t incell_intf_type_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc = INCELL_OK, mode; + incell_intf_mode intf_mode; + + rc = kstrtoint(buf, 10, &mode); + if (rc < 0) { + pr_err("%s: Error, buf = %s\n", __func__, buf); + return rc; + } + + intf_mode = (incell_intf_mode)(mode); + pr_notice("%s: buf = %s\n", __func__, buf); + rc = incell_control_mode(intf_mode, INCELL_FORCE); + pr_notice("%s: Incell execution %s\n", __func__, + rc == INCELL_OK ? "suscess" : "fail"); + pr_notice("%s: return %d\n", __func__, rc); + return count; +} + +static ssize_t incell_power_lock_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc = INCELL_OK, mode; + incell_pw_lock intf_lock; + incell_pw_status power_status; + + rc = kstrtoint(buf, 10, &mode); + if (rc < 0) { + pr_err("%s: Error, buf = %s\n", __func__, buf); + return rc; + } + + intf_lock = (incell_pw_lock)(mode); + pr_notice("%s: buf = %s\n", __func__, buf); + rc = incell_power_lock_ctrl(mode, &power_status); + pr_notice("%s: Incell execution %s\n", __func__, + rc == INCELL_OK ? "suscess" : "fail"); + pr_notice("%s: return %d\n", __func__, rc); + return count; +} + +static ssize_t incell_ewu_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc = INCELL_OK, mode; + incell_ewu_mode intf_ewu; + + rc = kstrtoint(buf, 10, &mode); + if (rc < 0) { + pr_err("%s: Error, buf = %s\n", __func__, buf); + return rc; + } + + intf_ewu = (incell_ewu_mode)(mode); + pr_notice("%s: buf = %s\n", __func__, buf); + incell_ewu_mode_ctrl(intf_ewu); + pr_notice("%s: Incell execution %s\n", __func__, + rc == INCELL_OK ? "suscess" : "fail"); + pr_notice("%s: return %d\n", __func__, rc); + return count; +} + +static struct device_attribute incell_attributes[] = { + __ATTR(incell_status, S_IRUGO, incell_panel_status_show, NULL), + __ATTR(incell_intf, S_IWUSR|S_IWGRP, NULL, incell_intf_type_store), + __ATTR(incell_lock, S_IWUSR|S_IWGRP, NULL, incell_power_lock_store), + __ATTR(incell_ewu, S_IWUSR|S_IWGRP, NULL, incell_ewu_store), +}; + +static int incell_register_attributes(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(incell_attributes); i++) + if (device_create_file(dev, incell_attributes + i)) + goto err; + + return 0; + +err: + dev_err(dev, "%s: Unable to create interface\n", __func__); + for (--i; i >= 0 ; i--) + device_remove_file(dev, incell_attributes + i); + + return -ENODEV; +} + +static int incell_create_debugfs(struct msm_fb_data_type *mfd) +{ + int rc = 0; + char *path_name = "incell_dsi_panel"; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_ctl *ctl = mdata->ctl_off; + struct mdss_panel_data *pdata = ctl->panel_data; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); + if (!ctrl_pdata) { + pr_err("%s: Invalid input data\n", __func__); + rc = -EINVAL; + goto out; + } + + dev_set_name(&incelldev, "%s", path_name); + rc = device_register(&incelldev); + if (rc) { + pr_err("%s: device_register rc = %d\n", __func__, rc); + goto out; + } + + rc = incell_register_attributes(&incelldev); + if (rc) { + pr_err("%s: register_attributes rc = %d\n", __func__, rc); + goto err; + } + + dev_set_drvdata(&incelldev, ctrl_pdata); + goto out; + +err: + device_unregister(&incelldev); +out: + return rc; +} + +static ssize_t mdss_dsi_panel_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + char const *id = ctrl_pdata->panel_data.panel_info.panel_id_name ? + ctrl_pdata->panel_data.panel_info.panel_id_name : "default"; + + return scnprintf(buf, PAGE_SIZE, "%s\n", id); +} + +static ssize_t mdss_dsi_panel_pcc_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + struct mdss_pcc_data *pcc_data; + u32 r, g, b; + + ctrl_pdata = mdss_dsi_get_master_ctrl(&ctrl_pdata->panel_data); + pcc_data = &ctrl_pdata->spec_pdata->pcc_data; + + r = g = b = 0; + if (!pcc_data->color_tbl) { + pr_err("%s: Panel has no color table\n", __func__); + goto exit; + } + if (pcc_data->u_data == 0 && pcc_data->v_data == 0) { + pr_err("%s: u,v are 0.\n", __func__); + goto exit; + } + if (pcc_data->tbl_idx >= pcc_data->tbl_size) { + pr_err("%s: Invalid color area(idx=%d)\n", + __func__, pcc_data->tbl_idx); + goto exit; + } + if (pcc_data->color_tbl[pcc_data->tbl_idx].color_type == UNUSED) { + pr_err("%s: Unsupported color type(idx=%d)\n", + __func__, pcc_data->tbl_idx); + goto exit; + } + r = pcc_data->color_tbl[pcc_data->tbl_idx].r_data; + g = pcc_data->color_tbl[pcc_data->tbl_idx].g_data; + b = pcc_data->color_tbl[pcc_data->tbl_idx].b_data; +exit: + return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x ", r, g, b); +} + +static ssize_t mdss_dsi_panel_srgb_pcc_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + struct mdss_pcc_data *pcc_data; + u32 r, g, b; + + ctrl_pdata = mdss_dsi_get_master_ctrl(&ctrl_pdata->panel_data); + pcc_data = &ctrl_pdata->spec_pdata->srgb_pcc_data; + + r = g = b = 0; + if (!pcc_data->color_tbl) { + pr_err("%s: Panel has no color table\n", __func__); + goto exit; + } + if (pcc_data->u_data == 0 && pcc_data->v_data == 0) { + pr_err("%s: u,v are 0.\n", __func__); + goto exit; + } + if (pcc_data->tbl_idx >= pcc_data->tbl_size) { + pr_err("%s: Invalid color area(idx=%d)\n", + __func__, pcc_data->tbl_idx); + goto exit; + } + if (pcc_data->color_tbl[pcc_data->tbl_idx].color_type == UNUSED) { + pr_err("%s: Unsupported color type(idx=%d)\n", + __func__, pcc_data->tbl_idx); + goto exit; + } + r = pcc_data->color_tbl[pcc_data->tbl_idx].r_data; + g = pcc_data->color_tbl[pcc_data->tbl_idx].g_data; + b = pcc_data->color_tbl[pcc_data->tbl_idx].b_data; +exit: + return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x ", r, g, b); +} + +static ssize_t mdss_dsi_panel_vivid_pcc_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + struct mdss_pcc_data *pcc_data; + u32 r, g, b; + + ctrl_pdata = mdss_dsi_get_master_ctrl(&ctrl_pdata->panel_data); + pcc_data = &ctrl_pdata->spec_pdata->vivid_pcc_data; + + r = g = b = 0; + if (!pcc_data->color_tbl) { + pr_err("%s: Panel has no color table\n", __func__); + goto exit; + } + if (pcc_data->u_data == 0 && pcc_data->v_data == 0) { + pr_err("%s: u,v are 0.\n", __func__); + goto exit; + } + if (pcc_data->tbl_idx >= pcc_data->tbl_size) { + pr_err("%s: Invalid color area(idx=%d)\n", + __func__, pcc_data->tbl_idx); + goto exit; + } + if (pcc_data->color_tbl[pcc_data->tbl_idx].color_type == UNUSED) { + pr_err("%s: Unsupported color type(idx=%d)\n", + __func__, pcc_data->tbl_idx); + goto exit; + } + r = pcc_data->color_tbl[pcc_data->tbl_idx].r_data; + g = pcc_data->color_tbl[pcc_data->tbl_idx].g_data; + b = pcc_data->color_tbl[pcc_data->tbl_idx].b_data; +exit: + return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x ", r, g, b); +} + +static ssize_t mdss_dsi_panel_hdr_pcc_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + struct mdss_pcc_data *pcc_data; + u32 r, g, b; + + ctrl_pdata = mdss_dsi_get_master_ctrl(&ctrl_pdata->panel_data); + pcc_data = &ctrl_pdata->spec_pdata->hdr_pcc_data; + + r = g = b = 0; + if (!pcc_data->color_tbl) { + pr_err("%s: Panel has no color table\n", __func__); + goto exit; + } + if (pcc_data->u_data == 0 && pcc_data->v_data == 0) { + pr_err("%s: u,v are 0.\n", __func__); + goto exit; + } + if (pcc_data->tbl_idx >= pcc_data->tbl_size) { + pr_err("%s: Invalid color area(idx=%d)\n", + __func__, pcc_data->tbl_idx); + goto exit; + } + if (pcc_data->color_tbl[pcc_data->tbl_idx].color_type == UNUSED) { + pr_err("%s: Unsupported color type(idx=%d)\n", + __func__, pcc_data->tbl_idx); + goto exit; + } + r = pcc_data->color_tbl[pcc_data->tbl_idx].r_data; + g = pcc_data->color_tbl[pcc_data->tbl_idx].g_data; + b = pcc_data->color_tbl[pcc_data->tbl_idx].b_data; +exit: + return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x ", r, g, b); +} + +static ssize_t mdss_dsi_panel_color_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdss_panel_specific_pdata *spec_pdata; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + + ctrl_pdata = mdss_dsi_get_master_ctrl(&ctrl_pdata->panel_data); + spec_pdata = ctrl_pdata->spec_pdata; + + return scnprintf(buf, PAGE_SIZE, "%d", spec_pdata->color_mode); +} + +static ssize_t mdss_dsi_panel_color_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mdss_panel_specific_pdata *spec_pdata; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + int mode, rc = 0; + + ctrl_pdata = mdss_dsi_get_master_ctrl(&ctrl_pdata->panel_data); + spec_pdata = ctrl_pdata->spec_pdata; + + if (sscanf(buf, "%d", &mode) < 0) { + pr_err("sscanf failed to set mode. keep current mode=%d\n", + spec_pdata->color_mode); + rc = -EINVAL; + goto exit; + } + + switch (mode) { + case CLR_MODE_SELECT_SRGB: + case CLR_MODE_SELECT_DCIP3: + case CLR_MODE_SELECT_PANELNATIVE: + spec_pdata->color_mode = mode; + break; + default: + pr_err("failed set mode:invalid mode=%d. keep current mode" + "=%d\n", mode, spec_pdata->color_mode); + rc = -EINVAL; + break; + } + +exit: + return !rc ? count : rc; + +} + +static ssize_t mdss_dsi_panel_frame_counter(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fps_data fpsd = mdss_dsi_panel_driver_get_fps_data(); + + return scnprintf(buf, PAGE_SIZE, "%i\n", fpsd.frame_counter); +} + +static ssize_t mdss_dsi_panel_frames_per_ksecs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fps_data fpsd = mdss_dsi_panel_driver_get_fps_data(); + + return scnprintf(buf, PAGE_SIZE, "%i\n", fpsd.fpks); +} + +static ssize_t mdss_dsi_panel_vsyncs_per_ksecs_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return mdss_dsi_panel_driver_vsyncs_per_ksecs_store(dev, buf, count); +} + +static ssize_t mdss_dsi_panel_vsyncs_per_ksecs_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fps_data vpsd = mdss_dsi_panel_driver_get_vps_data(); + + if (vpsd.vps_en) + return scnprintf(buf, PAGE_SIZE, "%i\n", vpsd.fpks); + else + return scnprintf(buf, PAGE_SIZE, + "This function is invalid now.\n" + "Please read again after writing ON.\n"); +} + +static ssize_t mdss_dsi_panel_change_fpks_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return mdss_dsi_panel_driver_change_fpks_store(dev, attr, buf, count); +} + +static ssize_t mdss_dsi_panel_change_fpks_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mdss_dsi_panel_driver_change_fpks_show(dev, attr, buf); +} + +static ssize_t mdss_dsi_panel_change_fps_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return mdss_dsi_panel_driver_change_fps_store(dev, attr, buf, count); +} + +static ssize_t mdss_dsi_panel_change_fps_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mdss_dsi_panel_driver_change_fps_show(dev, attr, buf); +} + +static ssize_t mdss_dsi_panel_esd_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdss_panel_specific_pdata *spec_pdata; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + + ctrl_pdata = mdss_dsi_get_master_ctrl(&ctrl_pdata->panel_data); + spec_pdata = ctrl_pdata->spec_pdata; + + return scnprintf(buf, PAGE_SIZE, "esd_enable = %u\n", + spec_pdata->esd_enable_without_xlog); +} + +static ssize_t mdss_dsi_panel_esd_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc = 0; + struct mdss_panel_specific_pdata *spec_pdata; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + + ctrl_pdata = mdss_dsi_get_master_ctrl(&ctrl_pdata->panel_data); + spec_pdata = ctrl_pdata->spec_pdata; + + rc = kstrtouint(buf, 10, &spec_pdata->esd_enable_without_xlog); + if (rc < 0) { + pr_err("%s: Error, buf = %s\n", __func__, buf); + return rc; + } + pr_notice("%s: esd_enable = %u\n", + __func__, spec_pdata->esd_enable_without_xlog); + return count; +} + +static struct device_attribute panel_attributes[] = { + __ATTR(panel_id, S_IRUSR, mdss_dsi_panel_id_show, NULL), + __ATTR(cc, S_IRUGO, mdss_dsi_panel_pcc_show, NULL), + __ATTR(srgb_cc, S_IRUGO, mdss_dsi_panel_srgb_pcc_show, NULL), + __ATTR(vivid_cc, S_IRUGO, mdss_dsi_panel_vivid_pcc_show, NULL), + __ATTR(hdr_cc, S_IRUGO, mdss_dsi_panel_hdr_pcc_show, NULL), + __ATTR(c_mode, S_IRUGO|S_IWUSR|S_IWGRP, + mdss_dsi_panel_color_mode_show, + mdss_dsi_panel_color_mode_store), + __ATTR(frame_counter, S_IRUGO, mdss_dsi_panel_frame_counter, NULL), + __ATTR(frames_per_ksecs, S_IRUGO, + mdss_dsi_panel_frames_per_ksecs, NULL), + __ATTR(vsyncs_per_ksecs, S_IRUSR|S_IRGRP|S_IWUSR|S_IWGRP, + mdss_dsi_panel_vsyncs_per_ksecs_show, + mdss_dsi_panel_vsyncs_per_ksecs_store), + __ATTR(change_fps, S_IRUGO|S_IWUSR|S_IWGRP, + mdss_dsi_panel_change_fps_show, + mdss_dsi_panel_change_fps_store), + __ATTR(change_fpks, S_IRUGO|S_IWUSR|S_IWGRP, + mdss_dsi_panel_change_fpks_show, + mdss_dsi_panel_change_fpks_store), + __ATTR(esd_enable_wo_xlog, S_IRUSR|S_IRGRP|S_IWUSR|S_IWGRP, + mdss_dsi_panel_esd_enable_show, + mdss_dsi_panel_esd_enable_store), +}; + +static int register_attributes(struct device *dev) +{ + int i; + for (i = 0; i < ARRAY_SIZE(panel_attributes); i++) + if (device_create_file(dev, panel_attributes + i)) + goto error; + return 0; +error: + dev_err(dev, "%s: Unable to create interface\n", __func__); + for (--i; i >= 0 ; i--) + device_remove_file(dev, panel_attributes + i); + return -ENODEV; +} + +int mdss_dsi_panel_create_fs(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + int rc = 0; + char *path_name = "mdss_dsi_panel"; + + dev_set_name(&virtdev, "%s", path_name); + rc = device_register(&virtdev); + if (rc) { + pr_err("%s: device_register rc = %d\n", __func__, rc); + goto err; + } + + rc = register_attributes(&virtdev); + if (rc) { + pr_err("%s: register_attributes rc = %d\n", __func__, rc); + device_unregister(&virtdev); + goto err; + } + + dev_set_drvdata(&virtdev, ctrl_pdata); + +err: + return rc; +} + +static void blackscreen_det_init(void) +{ + bs_det.threshold = DEFAULT_BS_THRESHOLD; + bs_det.cnt_crash = 0; + bs_det.cnt_timeout = 0; + memset(&bs_det.timestamp, 0x00, sizeof(ktime_t)); + bs_det.done = 0; + init_waitqueue_head(&bs_det.wait_queue); +} + +static void first_frame_flushed_det_init(void) +{ + memset(&fff_det.timestamp, 0x00, sizeof(ktime_t)); + fff_det.done = 0; + init_waitqueue_head(&fff_det.wait_queue); +} + +static void crash_counter_reset(void) +{ + bs_det.cnt_crash = 0; +} + +static void mdss_dsi_panel_blackscreen_det(void) +{ + bs_det.cnt_timeout++; + bs_det.cnt_crash++; + bs_det.timestamp = ktime_get_boottime(); + bs_det.done = 1; + wake_up(&bs_det.wait_queue); + + if (bs_det.cnt_crash > bs_det.threshold) + panic("[BScreenD] : panel command timeout error expired"); +} + +static void mdss_dsi_panel_fff_time_update( + struct mdss_panel_specific_pdata *spec_pdata) +{ + fff_det.timestamp = ktime_get_boottime(); + spec_pdata->resume_started = false; + fff_det.done = 1; + wake_up(&fff_det.wait_queue); +} + +static char *format_timestamp(ktime_t timestamp) +{ + static char buf[20]; + + scnprintf(buf, sizeof(buf), "%lld", ktime_to_ms(timestamp)); + return &buf[0]; +} + +static int bs_threshold_show(struct seq_file *s, void *unused) +{ + struct msm_fb_data_type *mfd = s->private; + struct mdss_panel_data *pdata; + struct mdss_dsi_ctrl_pdata *ctrl_pdata; + struct mdss_panel_info *pinfo; + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("%s: no panel connected\n", __func__); + goto exit; + } + + ctrl_pdata = mdss_dsi_get_master_ctrl(pdata); + if (!ctrl_pdata) { + pr_err("%s: Invalid input data\n", __func__); + goto exit; + } + pinfo = &ctrl_pdata->panel_data.panel_info; + + if (pinfo->mipi.mode == DSI_CMD_MODE) { + seq_printf(s, "%d\n", + bs_det.threshold); + } else { + seq_printf(s, "VideoMode isn't supported\n"); + } +exit: + return 0; +} + +static int timeout_counter_show(struct seq_file *s, void *unused) +{ + struct msm_fb_data_type *mfd = s->private; + struct mdss_panel_data *pdata; + struct mdss_dsi_ctrl_pdata *ctrl_pdata; + struct mdss_panel_info *pinfo; + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("%s: no panel connected\n", __func__); + goto exit; + } + + ctrl_pdata = mdss_dsi_get_master_ctrl(pdata); + if (!ctrl_pdata) { + pr_err("%s: Invalid input data\n", __func__); + goto exit; + } + pinfo = &ctrl_pdata->panel_data.panel_info; + + if (pinfo->mipi.mode == DSI_CMD_MODE) { + seq_printf(s, "%s %d\n", + format_timestamp(bs_det.timestamp), bs_det.cnt_timeout); + } else { + seq_printf(s, "VideoMode isn't supported\n"); + } +exit: + return 0; +} + +static int crash_counter_show(struct seq_file *s, void *unused) +{ + struct msm_fb_data_type *mfd = s->private; + struct mdss_panel_data *pdata; + struct mdss_dsi_ctrl_pdata *ctrl_pdata; + struct mdss_panel_info *pinfo; + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("%s: no panel connected\n", __func__); + goto exit; + } + + ctrl_pdata = mdss_dsi_get_master_ctrl(pdata); + if (!ctrl_pdata) { + pr_err("%s: Invalid input data\n", __func__); + goto exit; + } + pinfo = &ctrl_pdata->panel_data.panel_info; + + if (pinfo->mipi.mode == DSI_CMD_MODE) { + seq_printf(s, "%d\n", + bs_det.cnt_crash); + } else { + seq_printf(s, "VideoMode isn't supported\n"); + } +exit: + return 0; +} + +static int fff_time_show(struct seq_file *s, void *unused) +{ + seq_printf(s, "%s\n", + format_timestamp(fff_det.timestamp)); + return 0; +} + +static int bs_threshold_open(struct inode *inode, struct file *file) +{ + return single_open(file, bs_threshold_show, inode->i_private); +} + +static ssize_t bs_threshold_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct msm_fb_data_type *mfd = s->private; + struct mdss_panel_data *pdata; + int ret; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo; + char *buf = NULL; + u16 threshold; + + if (!mfd->panel_power_state) { + pr_err("%s: panel is NOT on\n", __func__); + ret = -EINVAL; + goto exit; + } + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("%s: no panel connected\n", __func__); + ret = -EINVAL; + goto exit; + } + + ctrl_pdata = mdss_dsi_get_master_ctrl(pdata); + if (!ctrl_pdata) { + pr_err("%s: Invalid input data\n", __func__); + ret = -EINVAL; + goto exit; + } + pinfo = &ctrl_pdata->panel_data.panel_info; + + if (pinfo->mipi.mode == DSI_CMD_MODE) { + ret = setup_reg_access(&buf, ubuf, count); + if (ret) { + pr_err("%s: Error, setup_reg_access\n", __func__); + ret = -EINVAL; + goto exit; + } + if (kstrtou16(buf, 10, &threshold)) { + pr_err("%s: Error, buf = %s\n", __func__, buf); + ret = -EINVAL; + goto fail_free_all; + } + pr_err("%s: threshold = %d\n", __func__, threshold); + ret = threshold; + bs_det.threshold = threshold; + + if (bs_det.cnt_crash > bs_det.threshold) + pr_notice("crash_counter is already beyond threshold\n"); + } else { + pr_err("VideoMode isn't supported\n"); + ret = -EINVAL; + goto exit; + } + +fail_free_all: + kzfree(buf); +exit: + return ret; +} + +static void mdss_dsi_panel_black_screen_off( + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + ctrl_pdata->spec_pdata->resume_started = true; +} + +static const struct file_operations bs_threshold_fops = { + .owner = THIS_MODULE, + .open = bs_threshold_open, + .read = seq_read, + .write = bs_threshold_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int timeout_counter_open(struct inode *inode, struct file *file) +{ + return single_open(file, timeout_counter_show, inode->i_private); +} + +static unsigned int timeout_counter_poll(struct file *filp, + struct poll_table_struct *wait) +{ + unsigned int mask = 0; + + poll_wait(filp, &bs_det.wait_queue, wait); + if (bs_det.done) { + mask |= (POLLIN | POLLRDNORM); + bs_det.done = 0; + } + + return mask; +} + +static const struct file_operations timeout_counter_fops = { + .owner = THIS_MODULE, + .open = timeout_counter_open, + .read = seq_read, + .llseek = seq_lseek, + .poll = timeout_counter_poll, + .release = single_release, +}; + +static int crash_counter_open(struct inode *inode, struct file *file) +{ + return single_open(file, crash_counter_show, inode->i_private); +} + +static const struct file_operations crash_counter_fops = { + .owner = THIS_MODULE, + .open = crash_counter_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int fff_time_open(struct inode *inode, struct file *file) +{ + return single_open(file, fff_time_show, inode->i_private); +} + +static unsigned int fff_time_poll(struct file *filp, + struct poll_table_struct *wait) +{ + unsigned int mask = 0; + + poll_wait(filp, &fff_det.wait_queue, wait); + if (fff_det.done) { + mask |= (POLLIN | POLLRDNORM); + fff_det.done = 0; + } + + return mask; +} + +static const struct file_operations fff_time_fops = { + .owner = THIS_MODULE, + .open = fff_time_open, + .read = seq_read, + .llseek = seq_lseek, + .poll = fff_time_poll, + .release = single_release, +}; +static void mipi_dsi_panel_create_debugfs(struct msm_fb_data_type *mfd) +{ + struct device *dev; + struct dentry *root; + struct mdss_panel_data *pdata; + struct platform_device *pdev; + struct mdss_panel_specific_pdata *spec_pdata; + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("%s: no panel connected\n", __func__); + return; + } + + blackscreen_det_init(); + first_frame_flushed_det_init(); + spec_pdata = mdss_panel2spec_pdata(pdata); + spec_pdata->crash_counter_reset = crash_counter_reset; + spec_pdata->blackscreen_det = mdss_dsi_panel_blackscreen_det; + spec_pdata->fff_time_update = mdss_dsi_panel_fff_time_update; + spec_pdata->black_screen_off = mdss_dsi_panel_black_screen_off; + spec_pdata->resume_started = false; + + pdev = pdata->panel_pdev; + if (!pdev) { + pr_err("%s: no device\n", __func__); + return; + } + + dev = &pdev->dev; + + if (!&dev->kobj) { + pr_err("%s: no &dev->kobj\n", __func__); + return; + } + + mdss_dsi_buf_alloc(dev, &debug_tx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K)); + mdss_dsi_buf_alloc(dev, &debug_rx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K)); + + dev_notice(dev, "%s: create folder %s\n", __func__, + kobject_name(&dev->kobj)); + + root = debugfs_create_dir("mdss_dsi_panel", 0); + + if (!root) { + dev_err(dev, "%s: dbgfs create dir failed\n", __func__); + } else { + if (!debugfs_create_file("read", S_IWUSR, root, mfd, + &read_fops)) { + dev_err(dev, "%s: failed to create dbgfs read file\n", + __func__); + return; + } + if (!debugfs_create_file("write", S_IWUSR, root, mfd, + &write_fops)) { + dev_err(dev, "%s: failed to create dbgfs write file\n", + __func__); + return; + } + if (!debugfs_create_file("result", S_IRUGO, root, mfd, + &result_fops)) { + dev_err(dev, "%s: failed to create dbgfs result file\n", + __func__); + return; + } + if (!debugfs_create_file("bs_threshold", S_IRUGO|S_IWUSR, root, + mfd, &bs_threshold_fops)) { + dev_err(dev, + "%s: failed to create dbgfs bs_threshold file\n", + __func__); + return; + } + if (!debugfs_create_file("timeout_counter", S_IRUGO, root, mfd, + &timeout_counter_fops)) { + dev_err(dev, + "%s: failed to create dbgfs timeout_counter file\n", + __func__); + return; + } + if (!debugfs_create_file("crash_counter", S_IRUGO, root, mfd, + &crash_counter_fops)) { + dev_err(dev, + "%s: failed to create dbgfs crash_counter file\n", + __func__); + return; + } + if (!debugfs_create_file("fff_time", S_IRUGO, root, mfd, + &fff_time_fops)) { + dev_err(dev, "%s: failed to create dbgfs fff_time file\n", + __func__); + return; + } + } +} + +int mdss_dsi_create_debugfs(struct msm_fb_data_type *mfd) +{ + int rc; + + mipi_dsi_panel_create_debugfs(mfd); + + rc = incell_create_debugfs(mfd); + if (rc) { + pr_err("%s: incell_create_debugfs rc = %d\n", __func__, rc); + goto out; + } +out: + return rc; +} diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel_debugfs.h b/drivers/video/fbdev/msm/mdss_dsi_panel_debugfs.h new file mode 100644 index 0000000000000000000000000000000000000000..968d1362501eeef6849e5401a8b200d956330375 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_dsi_panel_debugfs.h @@ -0,0 +1,39 @@ +/* + * drivers/video/fbdev/msm/mdss_dsi_panel_debugfs.h + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef MDSS_DSI_PANEL_DEBUGFS_H +#define MDSS_DSI_PANEL_DEBUGFS_H + +#include "mdss_dsi.h" + +struct blackscreen_det { + u16 threshold; + u16 cnt_timeout; + u16 cnt_crash; + ktime_t timestamp; + int done; + wait_queue_head_t wait_queue; +}; + +struct first_frame_flushed_det { + ktime_t timestamp; + int done; + wait_queue_head_t wait_queue; +}; + +int mdss_dsi_panel_create_fs(struct mdss_dsi_ctrl_pdata *ctrl_pdata); +int mdss_dsi_create_debugfs(struct msm_fb_data_type *mfd); +#endif /* MDSS_DSI_PANEL_DEBUGFS_H */ diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel_driver.c b/drivers/video/fbdev/msm/mdss_dsi_panel_driver.c new file mode 100644 index 0000000000000000000000000000000000000000..956b8b3427d73af876f5952bf1b46a2b6e7d24b1 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_dsi_panel_driver.c @@ -0,0 +1,2849 @@ +/* drivers/video/fbdev/msm/mdss_dsi_panel_driver.c + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdss.h" +#include "mdss_panel.h" +#include "mdss_dsi.h" +#include "mdss_debug.h" +#include "mdss_dsi_panel_driver.h" +#include "mdss_dsi_panel_debugfs.h" +#include + +static bool gpio_req; +static u32 down_period; + +static struct fps_data fpsd, vpsd; + +#define ADC_PNUM 2 +#define ADC_RNG_MIN 0 +#define ADC_RNG_MAX 1 + +#define NODE_OF_HYBRID "/soc/dsi_panel_pwr_supply_hybrid_incell" +#define NODE_OF_FULL "/soc/dsi_panel_pwr_supply_full_incell" + +static unsigned long lcdid_adc = 1505000; +static void vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t); + +static struct mdss_mdp_vsync_handler vs_handle; +static bool display_onoff_state; + +static int __init lcdid_adc_setup(char *str) +{ + unsigned long res; + + if (!*str) + return 0; + if (!kstrtoul(str, 0, &res)) + lcdid_adc = res; + + return 1; +} +__setup("lcdid_adc=", lcdid_adc_setup); + +void mdss_dsi_panel_driver_detection( + struct platform_device *pdev, + struct device_node **np) +{ + u32 res[ADC_PNUM]; + int rc = 0; + struct device_node *parent; + struct device_node *next; + u32 dev_index = 0; + u32 dsi_index = 0; + u32 adc_uv = 0; + + rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &dev_index); + if (rc) { + dev_err(&pdev->dev, + "%s: Cell-index not specified, rc=%d\n", + __func__, rc); + return; + } + + parent = of_get_parent(*np); + + adc_uv = lcdid_adc; + pr_notice("%s: physical:%d\n", __func__, adc_uv); + + for_each_child_of_node(parent, next) { + rc = of_property_read_u32(next, "somc,dsi-index", &dsi_index); + if (rc) + dsi_index = 0; + if (dsi_index != dev_index) + continue; + + rc = of_property_read_u32_array(next, + "somc,lcd-id-adc", res, ADC_PNUM); + if (rc) + continue; + if (adc_uv < res[ADC_RNG_MIN] || res[ADC_RNG_MAX] < adc_uv) + continue; + + *np = next; + break; + } +} + +static int mdss_dsi_panel_driver_vreg_name_to_config( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, + struct dss_vreg *config, char *name) +{ + struct dss_vreg *vreg_config = ctrl_pdata->panel_power_data.vreg_config; + int num_vreg = ctrl_pdata->panel_power_data.num_vreg; + int i = 0; + int valid = -EINVAL; + + for (i = 0; i < num_vreg; i++) { + if (!strcmp(name, vreg_config[i].vreg_name)) { + *config = vreg_config[i]; + valid = 0; + break; + } + } + + return valid; +} + +static int mdss_dsi_panel_driver_vreg_ctrl( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, char *vreg, bool enable) +{ + struct dss_vreg vreg_config; + struct mdss_panel_power_seq *pw_seq = NULL; + int valid = 0; + int wait = 0; + int ret = 0; + + valid = mdss_dsi_panel_driver_vreg_name_to_config( + ctrl_pdata, &vreg_config, vreg); + + if (!valid) { + if (enable) { + ret = msm_dss_enable_vreg(&vreg_config, 1, 1); + pw_seq = &ctrl_pdata->spec_pdata->on_seq; + } else { + ret = msm_dss_enable_vreg(&vreg_config, 1, 0); + pw_seq = &ctrl_pdata->spec_pdata->off_seq; + } + + if (!strcmp(vreg, "vdd")) + wait = pw_seq->disp_vdd; + else if (!strcmp(vreg, "vddio")) + wait = pw_seq->disp_vddio; + else if (!strcmp(vreg, "lab")) + wait = pw_seq->disp_vsp; + else if (!strcmp(vreg, "ibb")) + wait = pw_seq->disp_vsn; + else if (!strcmp(vreg, "touch-avdd")) + wait = pw_seq->touch_avdd; + else + wait = 0; + + if (!ret && wait) + usleep_range(wait * 1000, wait * 1000 + 100); + } + + return ret; +} + +bool mdss_dsi_panel_driver_is_power_on(unsigned char state) +{ + bool ret = false; + + if (state & INCELL_POWER_STATE_ON) + ret = true; + + pr_debug("%s: In-Cell %s state\n", __func__, (ret ? "on" : "off")); + + return ret; +} + +bool mdss_dsi_panel_driver_is_power_lock(unsigned char state) +{ + bool ret = false; + + if (state & INCELL_LOCK_STATE_ON) + ret = true; + + pr_debug("%s: In-Cell I/F %s state\n", __func__, + (ret ? "Lock" : "Unlock")); + + return ret; +} + +bool mdss_dsi_panel_driver_is_ewu(unsigned char state) +{ + bool ret = false; + + if (state & INCELL_EWU_STATE_ON) + ret = true; + + pr_debug("%s: In-Cell I/F %s state\n", __func__, + (ret ? "EWU" : "NORMAL")); + + return ret; +} + +bool mdss_dsi_panel_driver_is_system_on(unsigned char state) +{ + bool ret = false; + + if (state & INCELL_SYSTEM_STATE_ON) + ret = true; + + pr_debug("%s: In-Cell system %s state\n", __func__, + (ret ? "resume" : "suspend")); + + return ret; +} + +static bool mdss_dsi_panel_driver_is_seq_for_ewu(void) +{ + struct incell_ctrl *incell = incell_get_info(); + + if (incell && + (incell->seq == POWER_ON_EWU_SEQ)) + return true; + + return false; +} + +static bool mdss_dsi_panel_driver_is_incell_operation(void) +{ + struct incell_ctrl *incell = incell_get_info(); + + if (incell && + (incell->incell_intf_operation == INCELL_TOUCH_RUN)) + return true; + + return false; +} + +static int mdss_dsi_panel_calculation_sleep( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, + int gpio, bool enable) +{ + struct mdss_panel_specific_pdata *spec_pdata = ctrl_pdata->spec_pdata; + struct mdss_panel_power_seq *pw_seq = NULL; + int wait = 0; + + if (mdss_dsi_panel_driver_is_seq_for_ewu() && + (gpio == spec_pdata->touch_reset_gpio) && + !enable) { + if (&spec_pdata->ewu_seq) + pw_seq = &spec_pdata->ewu_seq; + else + pw_seq = &spec_pdata->on_seq; + } else { + if (enable) + pw_seq = &spec_pdata->on_seq; + else + pw_seq = &spec_pdata->off_seq; + } + + if (gpio == spec_pdata->disp_dcdc_en_gpio) + wait = pw_seq->disp_dcdc; + else if (gpio == spec_pdata->touch_vddio_gpio) + wait = pw_seq->touch_vddio; + else if (gpio == spec_pdata->touch_reset_gpio) + wait = pw_seq->touch_reset; + else if (gpio == spec_pdata->touch_int_gpio) + wait = pw_seq->touch_intn; + else + wait = 0; + + wait = wait * 1000; + return wait; +} + +static void mdss_dsi_panel_driver_gpio_output( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, + int gpio, bool enable, int value) +{ + int wait; + + wait = mdss_dsi_panel_calculation_sleep(ctrl_pdata, gpio, enable); + + if (gpio_is_valid(gpio)) + gpio_direction_output(gpio, value); + + if (wait) + usleep_range(wait, wait + 100); +} + +static void mdss_dsi_panel_driver_set_gpio( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, + int gpio, bool enable, int value) +{ + int wait = 0; + + wait = mdss_dsi_panel_calculation_sleep(ctrl_pdata, gpio, enable); + + if (gpio_is_valid(gpio)) + gpio_set_value(gpio, value); + + if (wait) + usleep_range(wait, wait + 100); +} + +int mdss_dsi_panel_driver_pinctrl_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + ctrl_pdata->pin_res.touch_state_active + = pinctrl_lookup_state(ctrl_pdata->pin_res.pinctrl, + MDSS_PINCTRL_STATE_TOUCH_ACTIVE); + if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.touch_state_active)) + pr_warn("%s: can not get touch active pinstate\n", __func__); + + ctrl_pdata->pin_res.touch_state_suspend + = pinctrl_lookup_state(ctrl_pdata->pin_res.pinctrl, + MDSS_PINCTRL_STATE_TOUCH_SUSPEND); + if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.touch_state_suspend)) + pr_warn("%s: can not get touch suspend pinstate\n", __func__); + + return 0; +} + +int mdss_dsi_panel_driver_touch_pinctrl_set_state( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, + bool active) +{ + struct mdss_panel_specific_pdata *spec_pdata = NULL; + struct pinctrl_state *pin_state; + int rc = -EFAULT; + int wait = 0; + + if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.pinctrl)) + return PTR_ERR(ctrl_pdata->pin_res.pinctrl); + + spec_pdata = ctrl_pdata->spec_pdata; + + pin_state = active ? ctrl_pdata->pin_res.touch_state_active + : ctrl_pdata->pin_res.touch_state_suspend; + + if (!IS_ERR_OR_NULL(pin_state)) { + rc = pinctrl_select_state(ctrl_pdata->pin_res.pinctrl, + pin_state); + if (!rc) { + wait = mdss_dsi_panel_calculation_sleep(ctrl_pdata, + spec_pdata->touch_int_gpio, active); + if (wait) + usleep_range(wait, wait + 100); + } else { + pr_err("%s: can not set %s pins\n", __func__, + active ? MDSS_PINCTRL_STATE_TOUCH_ACTIVE + : MDSS_PINCTRL_STATE_TOUCH_SUSPEND); + } + } else { + pr_err("%s: invalid '%s' pinstate\n", __func__, + active ? MDSS_PINCTRL_STATE_TOUCH_ACTIVE + : MDSS_PINCTRL_STATE_TOUCH_SUSPEND); + } + + return rc; +} + +void mdss_dsi_panel_driver_state_change_off(struct incell_ctrl *incell) +{ + incell_state_change change_state = incell->change_state; + unsigned char *state = &incell->state; + + pr_debug("%s: status:0x%x --->\n", __func__, (*state)); + + if (change_state != INCELL_STATE_NONE) + mdss_dsi_panel_driver_update_incell_bk(incell); + + switch (change_state) { + case INCELL_STATE_NONE: + pr_notice("%s: Not change off status\n", __func__); + break; + case INCELL_STATE_S_OFF: + *state &= INCELL_SYSTEM_STATE_OFF; + break; + case INCELL_STATE_P_OFF: + *state &= INCELL_POWER_STATE_OFF; + break; + case INCELL_STATE_SP_OFF: + *state &= INCELL_POWER_STATE_OFF; + *state &= INCELL_SYSTEM_STATE_OFF; + break; + default: + pr_err("%s: offmode unknown\n", __func__); + break; + } + + pr_debug("%s: ---> status:0x%x\n", __func__, (*state)); +} + +void mdss_dsi_panel_driver_power_off_ctrl(struct incell_ctrl *incell) +{ + incell_pw_seq seq = POWER_OFF_EXECUTE; + incell_state_change change_state = INCELL_STATE_NONE; + unsigned char state = incell->state; + incell_intf_mode intf_mode = incell->intf_mode; + incell_worker_state worker_state = incell->worker_state; + bool incell_intf_operation = incell->incell_intf_operation; + + if (worker_state == INCELL_WORKER_ON) { + change_state = INCELL_STATE_P_OFF; + } else if (incell_intf_operation == INCELL_TOUCH_RUN) { + /* touch I/F running mode */ + if (intf_mode == INCELL_DISPLAY_HW_RESET) { + if (!mdss_dsi_panel_driver_is_power_on(state)) { + pr_err("%s: Already power off. state:0x%x\n", + __func__, state); + seq = POWER_OFF_SKIP; + } else { + change_state = INCELL_STATE_P_OFF; + } + } else { + if (!mdss_dsi_panel_driver_is_power_on(state)) { + pr_err("%s: Power off status. state:0x%x\n", + __func__, state); + seq = POWER_OFF_SKIP; + } else if (mdss_dsi_panel_driver_is_ewu(state)) { + pr_debug("%s: Skip power off for EWU seq\n", + __func__); + seq = POWER_OFF_SKIP; + } else { + change_state = INCELL_STATE_P_OFF; + } + } + } else { + if (worker_state == INCELL_WORKER_PENDING) + incell_panel_power_worker_canceling(incell); + + /* touch I/F idling mode */ + if (mdss_dsi_panel_driver_is_power_lock(state)) { + change_state = INCELL_STATE_S_OFF; + seq = POWER_OFF_SKIP; + } else if (!mdss_dsi_panel_driver_is_power_on(state)) { + change_state = INCELL_STATE_S_OFF; + seq = POWER_OFF_SKIP; + } else if (mdss_dsi_panel_driver_is_ewu(state)) { + change_state = INCELL_STATE_S_OFF; + seq = POWER_OFF_SKIP; + } else { + change_state = INCELL_STATE_SP_OFF; + } + } + + pr_debug("%s: incell change state seq:%d change_state:%d\n", + __func__, (int)seq, (int)change_state); + incell->seq = seq; + incell->change_state = change_state; +} + +int mdss_dsi_panel_driver_power_off(struct mdss_panel_data *pdata) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_specific_pdata *spec_pdata = NULL; + struct mdss_panel_power_seq *pw_seq = NULL; + struct incell_ctrl *incell = incell_get_info(); + int ret = 0; + int rc = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + ret = -EINVAL; + goto end; + } + + if (incell) + if (incell->seq == POWER_OFF_SKIP) + return ret; + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + spec_pdata = ctrl_pdata->spec_pdata; + + pw_seq = &spec_pdata->off_seq; + + if (spec_pdata->off_seq.rst_b_seq) { + rc = mdss_dsi_panel_reset(pdata, 0); + if (rc) + pr_warn("%s: Panel reset failed. rc=%d\n", + __func__, rc); + } + + ret += mdss_dsi_panel_driver_reset_touch(pdata, 0); + ret += mdss_dsi_panel_driver_vreg_ctrl(ctrl_pdata, "ibb", false); + ret += mdss_dsi_panel_driver_vreg_ctrl(ctrl_pdata, "lab", false); + + mdss_dsi_panel_driver_set_gpio(ctrl_pdata, + (spec_pdata->disp_dcdc_en_gpio), false, 0); + + if (!spec_pdata->off_seq.rst_b_seq) { + rc = mdss_dsi_panel_reset(pdata, 0); + if (rc) + pr_warn("%s: Panel reset failed. rc=%d\n", + __func__, rc); + } + + mdss_dsi_panel_driver_touch_pinctrl_set_state(ctrl_pdata, false); + + mdss_dsi_panel_driver_set_gpio(ctrl_pdata, + (spec_pdata->touch_vddio_gpio), false, 1); + + ret += mdss_dsi_panel_driver_vreg_ctrl(ctrl_pdata, "vddio", false); + + ret += mdss_dsi_panel_driver_vreg_ctrl(ctrl_pdata, "touch-avdd", false); + + if (ret) + pr_err("%s: failed to disable vregs for %s\n", + __func__, __mdss_dsi_pm_name(DSI_PANEL_PM)); + else + pr_notice("@@@@ panel power off @@@@\n"); + + if (mdss_dsi_pinctrl_set_state(ctrl_pdata, false)) + pr_debug("reset disable: pinctrl not enabled\n"); + + if (spec_pdata->down_period) + down_period = (u32)ktime_to_ms(ktime_get()); + +end: + return ret; +} + +void mdss_dsi_panel_driver_state_change_on(struct incell_ctrl *incell) +{ + incell_state_change change_state = incell->change_state; + unsigned char *state = &incell->state; + + pr_debug("%s: status:0x%x --->\n", __func__, (*state)); + + if (change_state != INCELL_STATE_NONE) + mdss_dsi_panel_driver_update_incell_bk(incell); + + switch (change_state) { + case INCELL_STATE_NONE: + pr_notice("%s: Not change on status\n", __func__); + break; + case INCELL_STATE_S_ON: + *state |= INCELL_SYSTEM_STATE_ON; + break; + case INCELL_STATE_P_ON: + *state |= INCELL_POWER_STATE_ON; + break; + case INCELL_STATE_SP_ON: + *state |= INCELL_SYSTEM_STATE_ON; + *state |= INCELL_POWER_STATE_ON; + break; + default: + pr_err("%s: onmode unknown\n", __func__); + break; + } + + pr_debug("%s: ---> status:0x%x\n", __func__, (*state)); +} + +void mdss_dsi_panel_driver_power_on_ctrl(struct incell_ctrl *incell) +{ + incell_pw_seq seq = POWER_ON_EXECUTE; + incell_state_change change_state = INCELL_STATE_NONE; + unsigned char state = incell->state; + incell_intf_mode intf_mode = incell->intf_mode; + incell_worker_state worker_state = incell->worker_state; + bool incell_intf_operation = incell->incell_intf_operation; + + if (worker_state == INCELL_WORKER_ON) { + change_state = INCELL_STATE_P_ON; + } else if (incell_intf_operation == INCELL_TOUCH_RUN) { + /* touch I/F running mode */ + if (intf_mode != INCELL_DISPLAY_HW_RESET) { + pr_err("%s: Unknown I/F: %d\n", + __func__, (int)intf_mode); + seq = POWER_ON_SKIP; + } else if (mdss_dsi_panel_driver_is_power_on(state)) { + pr_err("%s: Already power on status. state:0x%x\n", + __func__, state); + seq = POWER_ON_SKIP; + } else { + change_state = INCELL_STATE_P_ON; + } + } else { + /* touch I/F idling mode */ + if (worker_state == INCELL_WORKER_PENDING) { + incell_panel_power_worker_canceling(incell); + change_state = INCELL_STATE_S_ON; + seq = POWER_ON_EWU_SEQ; + } else if (mdss_dsi_panel_driver_is_power_lock(state)) { + if (mdss_dsi_panel_driver_is_power_on(state)) { + change_state = INCELL_STATE_S_ON; + seq = POWER_ON_SKIP; + } else { + change_state = INCELL_STATE_SP_ON; + seq = POWER_ON_EXECUTE; + } + } else if (mdss_dsi_panel_driver_is_ewu(state)) { + if (mdss_dsi_panel_driver_is_power_on(state)) { + change_state = INCELL_STATE_S_ON; + seq = POWER_ON_EWU_SEQ; + } else { + change_state = INCELL_STATE_SP_ON; + seq = POWER_ON_EXECUTE; + } + } else if (mdss_dsi_panel_driver_is_power_on(state)) { + change_state = INCELL_STATE_S_ON; + seq = POWER_ON_EWU_SEQ; + } else { + change_state = INCELL_STATE_SP_ON; + seq = POWER_ON_EXECUTE; + } + } + + pr_debug("%s: incell change state seq:%d change_state:%d\n", + __func__, (int)seq, (int)change_state); + incell->seq = seq; + incell->change_state = change_state; +} + +static int mdss_dsi_panel_driver_ewu_seq(struct mdss_panel_data *pdata) +{ + int ret = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); + if (!ctrl_pdata) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ret += mdss_dsi_panel_driver_reset_touch(pdata, 0); + ret += mdss_dsi_panel_driver_reset_dual_display(ctrl_pdata); + + return ret; +} + +int mdss_dsi_panel_driver_power_on(struct mdss_panel_data *pdata) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_specific_pdata *spec_pdata = NULL; + struct mdss_panel_power_seq *pw_seq = NULL; + struct incell_ctrl *incell = incell_get_info(); + unsigned char state; + int ret = 0; + int wait; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + if (incell) { + mdss_dsi_panel_driver_power_on_ctrl(incell); + if (incell->seq != POWER_ON_EXECUTE) { + if (incell->seq == POWER_ON_EWU_SEQ) + ret = mdss_dsi_panel_driver_ewu_seq(pdata); + return ret; + } + state = incell->state; + } + + if (pdata->panel_info.pdest != DISPLAY_1) + return 0; + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + spec_pdata = ctrl_pdata->spec_pdata; + + pw_seq = &spec_pdata->on_seq; + + if (!gpio_req) { + ret = mdss_dsi_request_gpios(ctrl_pdata); + if (ret) { + pr_err("gpio request failed\n"); + return ret; + } + gpio_req = true; + } + + if (spec_pdata->down_period) { + u32 kt = (u32)ktime_to_ms(ktime_get()); + + kt = (kt < down_period) ? kt + ~down_period : kt - down_period; + if (kt < spec_pdata->down_period) + usleep_range((spec_pdata->down_period - kt) * + 1000, + (spec_pdata->down_period - kt) * + 1000 + 100); + } + + ret += mdss_dsi_panel_driver_vreg_ctrl(ctrl_pdata, "touch-avdd", true); + ret += mdss_dsi_panel_driver_vreg_ctrl(ctrl_pdata, "vddio", true); + + mdss_dsi_panel_driver_gpio_output(ctrl_pdata, + (spec_pdata->touch_vddio_gpio), true, 0); + + mdss_dsi_panel_driver_touch_pinctrl_set_state(ctrl_pdata, true); + + mdss_dsi_panel_driver_gpio_output(ctrl_pdata, + (spec_pdata->disp_dcdc_en_gpio), true, 1); + + if ((spec_pdata->panel_type == HYBRID_INCELL) && + (!mdss_dsi_panel_driver_is_power_on(state))) { + ret += mdss_dsi_panel_driver_reset_touch(pdata, 1); + wait = pw_seq->touch_reset_first; + usleep_range(wait * 1000, wait * 1000 + 100); + } + + ret += mdss_dsi_panel_driver_vreg_ctrl(ctrl_pdata, "lab", true); + ret += mdss_dsi_panel_driver_vreg_ctrl(ctrl_pdata, "ibb", true); + + if (ret) { + pr_err("%s: failed to enable vregs for %s\n", + __func__, __mdss_dsi_pm_name(DSI_PANEL_PM)); + return ret; + } + + pr_notice("@@@@ panel power on @@@@\n"); + + /* + * If continuous splash screen feature is enabled, then we need to + * request all the GPIOs that have already been configured in the + * bootloader. This needs to be done irresepective of whether + * the lp11_init flag is set or not. + */ + if (!pdata->panel_info.cont_splash_enabled && + !pdata->panel_info.mipi.lp11_init) { + if (mdss_dsi_pinctrl_set_state(ctrl_pdata, true)) + pr_debug("reset enable: pinctrl not enabled\n"); + + ret = mdss_dsi_panel_reset(pdata, 1); + if (ret) + pr_err("%s: Panel reset failed. rc=%d\n", + __func__, ret); + } + + return ret; +} + +int mdss_dsi_panel_driver_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct mdss_panel_specific_pdata *spec_pdata = NULL; + int rc = 0; + + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + spec_pdata = ctrl_pdata->spec_pdata; + + if (gpio_is_valid(spec_pdata->disp_vddio_gpio)) { + rc = gpio_request(spec_pdata->disp_vddio_gpio, + "disp_vddio"); + if (rc) { + pr_err("request disp vddio gpio failed, rc=%d\n", + rc); + goto disp_vddio_gpio_err; + } + } + + if (gpio_is_valid(spec_pdata->disp_dcdc_en_gpio)) { + rc = gpio_request(spec_pdata->disp_dcdc_en_gpio, + "disp_dcdc_en_gpio"); + if (rc) { + pr_err("request disp_dcdc_en gpio failed, rc=%d\n", rc); + goto disp_dcdc_en_gpio_err; + } + } + + if (gpio_is_valid(spec_pdata->touch_vddio_gpio)) { + rc = gpio_request(spec_pdata->touch_vddio_gpio, + "touch_vddio"); + if (rc) { + pr_err("request touch vddio gpio failed, rc=%d\n", + rc); + goto touch_vddio_gpio_err; + } + } + + if (gpio_is_valid(spec_pdata->touch_reset_gpio)) { + rc = gpio_request(spec_pdata->touch_reset_gpio, + "touch_reset"); + if (rc) { + pr_err("request touch reset gpio failed,rc=%d\n", + rc); + goto touch_reset_gpio_err; + } + } + + if (gpio_is_valid(spec_pdata->touch_int_gpio)) { + rc = gpio_request(spec_pdata->touch_int_gpio, + "touch_int"); + if (rc) { + pr_err("request touch int gpio failed,rc=%d\n", + rc); + goto touch_int_gpio_err; + } + } + + return rc; + +touch_int_gpio_err: + if (gpio_is_valid(spec_pdata->touch_reset_gpio)) + gpio_free(spec_pdata->touch_reset_gpio); +touch_reset_gpio_err: + if (gpio_is_valid(spec_pdata->touch_vddio_gpio)) + gpio_free(spec_pdata->touch_vddio_gpio); +touch_vddio_gpio_err: + if (gpio_is_valid(spec_pdata->disp_dcdc_en_gpio)) + gpio_free(spec_pdata->disp_dcdc_en_gpio); +disp_dcdc_en_gpio_err: + if (gpio_is_valid(spec_pdata->disp_vddio_gpio)) + gpio_free(spec_pdata->disp_vddio_gpio); +disp_vddio_gpio_err: + return rc; +} + +void mdss_dsi_panel_driver_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct mdss_panel_specific_pdata *spec_pdata = NULL; + + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + spec_pdata = ctrl_pdata->spec_pdata; + + if (gpio_is_valid(spec_pdata->touch_int_gpio)) + gpio_free(spec_pdata->touch_int_gpio); + + if (gpio_is_valid(spec_pdata->touch_reset_gpio)) + gpio_free(spec_pdata->touch_reset_gpio); + + if (gpio_is_valid(spec_pdata->touch_vddio_gpio)) + gpio_free(spec_pdata->touch_vddio_gpio); + + if (gpio_is_valid(spec_pdata->disp_dcdc_en_gpio)) + gpio_free(spec_pdata->disp_dcdc_en_gpio); + + if (gpio_is_valid(spec_pdata->disp_vddio_gpio)) + gpio_free(spec_pdata->disp_vddio_gpio); +} + +void mdss_dsi_panel_driver_parse_gpio_params(struct platform_device *ctrl_pdev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct mdss_panel_specific_pdata *spec_pdata = NULL; + + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + spec_pdata = ctrl_pdata->spec_pdata; + + spec_pdata->disp_vddio_gpio = of_get_named_gpio( + ctrl_pdev->dev.of_node, + "qcom,platform-vddio-gpio", 0); + + if (!gpio_is_valid(spec_pdata->disp_vddio_gpio)) + pr_err("%s:%d, disp vddio gpio not specified\n", + __func__, __LINE__); + + spec_pdata->touch_vddio_gpio = of_get_named_gpio( + ctrl_pdev->dev.of_node, + "qcom,platform-touch-vddio-gpio", 0); + + if (!gpio_is_valid(spec_pdata->touch_vddio_gpio)) + pr_err("%s:%d, touch vddio gpio not specified\n", + __func__, __LINE__); + + spec_pdata->touch_reset_gpio = of_get_named_gpio( + ctrl_pdev->dev.of_node, + "qcom,platform-touch-reset-gpio", 0); + + if (!gpio_is_valid(spec_pdata->touch_reset_gpio)) + pr_err("%s:%d, touch reset gpio not specified\n", + __func__, __LINE__); + + spec_pdata->touch_int_gpio = of_get_named_gpio( + ctrl_pdev->dev.of_node, + "qcom,platform-touch-int-gpio", 0); + + if (!gpio_is_valid(spec_pdata->touch_int_gpio)) + pr_err("%s:%d, touch int gpio not specified\n", + __func__, __LINE__); + + spec_pdata->disp_dcdc_en_gpio = of_get_named_gpio( + ctrl_pdev->dev.of_node, + "somc,disp-dcdc-en-gpio", 0); + + if (!gpio_is_valid(spec_pdata->disp_dcdc_en_gpio)) + pr_err("%s:%d, disp dcdc en gpio not specified\n", + __func__, __LINE__); +} + + +static void mdss_dsi_panel_set_gpio_seq( + int gpio, int seq_num, const int *seq) +{ + int i; + + for (i = 0; i + 1 < seq_num; i += 2) { + gpio_set_value(gpio, seq[i]); + usleep_range(seq[i + 1] * 1000, seq[i + 1] * 1000 + 100); + pr_debug("%s: enable=%d, wait=%dms\n", + __func__, seq[i], seq[i+1]); + } +} + +int mdss_dsi_panel_driver_reset_panel(struct mdss_panel_data *pdata, int enable) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo = NULL; + struct mdss_panel_power_seq *pw_seq = NULL; + int rc = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + if (!gpio_is_valid(ctrl_pdata->rst_gpio)) { + pr_debug("%s:%d, panel reset line not configured\n", + __func__, __LINE__); + return rc; + } + + pr_debug("%s: enable = %d\n", __func__, enable); + pinfo = &(ctrl_pdata->panel_data.panel_info); + + + if (!gpio_req) { + rc = mdss_dsi_request_gpios(ctrl_pdata); + if (rc) { + pr_err("gpio request failed\n"); + return rc; + } + gpio_req = true; + } + + if (mdss_dsi_panel_driver_is_seq_for_ewu() && enable) + pw_seq = &ctrl_pdata->spec_pdata->ewu_seq ? + &ctrl_pdata->spec_pdata->ewu_seq : + &ctrl_pdata->spec_pdata->on_seq; + else + pw_seq = (enable) ? &ctrl_pdata->spec_pdata->on_seq : + &ctrl_pdata->spec_pdata->off_seq; + + mdss_dsi_panel_set_gpio_seq(ctrl_pdata->rst_gpio, + pw_seq->seq_num, pw_seq->rst_seq); + + return rc; +} + +int mdss_dsi_panel_driver_reset_touch(struct mdss_panel_data *pdata, int enable) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo = NULL; + struct mdss_panel_specific_pdata *spec_pdata = NULL; + int rc = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + spec_pdata = ctrl_pdata->spec_pdata; + + if (!gpio_is_valid(spec_pdata->touch_reset_gpio)) { + pr_debug("%s:%d, touch reset line not configured\n", + __func__, __LINE__); + return rc; + } + + pr_debug("%s: enable = %d\n", __func__, enable); + pinfo = &(ctrl_pdata->panel_data.panel_info); + + if (enable) { + if (!gpio_req) { + rc = mdss_dsi_request_gpios(ctrl_pdata); + if (rc) { + pr_err("gpio request failed\n"); + return rc; + } + gpio_req = true; + } + + mdss_dsi_panel_driver_gpio_output(ctrl_pdata, + (spec_pdata->touch_reset_gpio), true, 1); + } else { + mdss_dsi_panel_driver_set_gpio(ctrl_pdata, + (spec_pdata->touch_reset_gpio), false, 0); + } + + return rc; +} + +static bool mdss_dsi_panel_driver_split_display_enabled(void) +{ + /* + * currently the only supported mode is split display. + * So, if both controllers are initialized, then assume that + * split display mode is enabled. + */ + return ctrl_list[DSI_CTRL_LEFT] && ctrl_list[DSI_CTRL_RIGHT]; +} + +int mdss_dsi_panel_driver_reset_dual_display( + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct mdss_dsi_ctrl_pdata *mctrl_pdata = NULL; + int ret = 0; + + if (!mdss_dsi_panel_driver_split_display_enabled()) { + if (mdss_dsi_pinctrl_set_state(ctrl_pdata, true)) + pr_debug("reset enable: pinctrl not enabled\n"); + ret = mdss_dsi_panel_reset(&(ctrl_pdata->panel_data), 1); + } else if (ctrl_pdata->ndx == DSI_CTRL_1) { + mctrl_pdata = mdss_dsi_get_other_ctrl(ctrl_pdata); + if (!mctrl_pdata) { + pr_warn("%s: Unable to get other control\n", + __func__); + ret = -EINVAL; + } else { + if (mdss_dsi_pinctrl_set_state(mctrl_pdata, true)) + pr_debug("other reset pinctrl not enabled\n"); + ret = mdss_dsi_panel_reset(&(mctrl_pdata->panel_data), 1); + } + } else { + pr_debug("%s: reset pinctrl not yet\n", __func__); + } + + return ret; +} + +static int mdss_dsi_property_read_u32_var(struct device_node *np, + char *name, u32 **out_data, int *num) +{ + struct property *prop = of_find_property(np, name, NULL); + const __be32 *val; + u32 *out; + int s; + + if (!prop) { + pr_debug("%s:%d, unable to read %s", __func__, __LINE__, name); + return -EINVAL; + } + if (!prop->value) { + pr_debug("%s:%d, no data of %s", __func__, __LINE__, name); + return -ENODATA; + } + + *num = prop->length / sizeof(u32); + if (!*num || *num % 2) { + pr_debug("%s:%d, error reading %s, length found = %d\n", + __func__, __LINE__, name, *num); + return -ENODATA; + } + *out_data = kzalloc(prop->length, GFP_KERNEL); + if (!*out_data) { + pr_err("%s:no mem assigned: kzalloc fail\n", __func__); + *num = 0; + return -ENOMEM; + } + + val = prop->value; + out = *out_data; + s = *num; + while (s--) + *out++ = be32_to_cpup(val++); + return 0; +} + +int mdss_dsi_panel_driver_parse_dt(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct mdss_panel_specific_pdata *spec_pdata = NULL; + struct mdss_panel_info *pinfo = NULL; + u32 tmp = 0; + int rc = 0; + struct device_node *panel_np; + const char *panel_type_name; + static const char *fps_mode; + static const char *fps_type; + struct mdss_panel_labibb_data *labibb = NULL; + + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + goto error; + } + + spec_pdata = ctrl_pdata->spec_pdata; + pinfo = &(ctrl_pdata->panel_data.panel_info); + + spec_pdata->pcc_enable = of_property_read_bool(np, "somc,mdss-dsi-pcc-enable"); + if (spec_pdata->pcc_enable) { + mdss_dsi_parse_dcs_cmds(np, &spec_pdata->pre_uv_read_cmds, + "somc,mdss-dsi-pre-uv-command", NULL); + + mdss_dsi_parse_dcs_cmds(np, &spec_pdata->uv_read_cmds, + "somc,mdss-dsi-uv-command", NULL); + + rc = of_property_read_u32(np, + "somc,mdss-dsi-uv-param-type", &tmp); + spec_pdata->pcc_data.param_type = + (!rc ? tmp : CLR_DATA_UV_PARAM_TYPE_NONE); + + rc = of_property_read_u32(np, + "somc,mdss-dsi-pcc-table-size", &tmp); + spec_pdata->pcc_data.tbl_size = + (!rc ? tmp : 0); + + spec_pdata->pcc_data.color_tbl = + kzalloc(spec_pdata->pcc_data.tbl_size * + sizeof(struct mdss_pcc_color_tbl), + GFP_KERNEL); + if (!spec_pdata->pcc_data.color_tbl) { + pr_err("no mem assigned: kzalloc fail\n"); + return -ENOMEM; + } + rc = of_property_read_u32_array(np, + "somc,mdss-dsi-pcc-table", + (u32 *)spec_pdata->pcc_data.color_tbl, + spec_pdata->pcc_data.tbl_size * + sizeof(struct mdss_pcc_color_tbl) / + sizeof(u32)); + if (rc) { + spec_pdata->pcc_data.tbl_size = 0; + kzfree(spec_pdata->pcc_data.color_tbl); + spec_pdata->pcc_data.color_tbl = NULL; + pr_err("%s:%d, Unable to read pcc table", + __func__, __LINE__); + } + spec_pdata->pcc_data.pcc_sts |= PCC_STS_UD; + } + + spec_pdata->srgb_pcc_enable = of_property_read_bool(np, + "somc,mdss-dsi-srgb-pcc-enable"); + if (spec_pdata->srgb_pcc_enable) { + rc = of_property_read_u32(np, + "somc,mdss-dsi-srgb-pcc-table-size", &tmp); + spec_pdata->srgb_pcc_data.tbl_size = + (!rc ? tmp : 0); + + spec_pdata->srgb_pcc_data.color_tbl = + kzalloc(spec_pdata->srgb_pcc_data.tbl_size * + sizeof(struct mdss_pcc_color_tbl), + GFP_KERNEL); + if (!spec_pdata->srgb_pcc_data.color_tbl) { + pr_err("no mem assigned: kzalloc fail\n"); + return -ENOMEM; + } + rc = of_property_read_u32_array(np, + "somc,mdss-dsi-srgb-pcc-table", + (u32 *)spec_pdata->srgb_pcc_data.color_tbl, + spec_pdata->srgb_pcc_data.tbl_size * + sizeof(struct mdss_pcc_color_tbl) / + sizeof(u32)); + if (rc) { + spec_pdata->srgb_pcc_data.tbl_size = 0; + kzfree(spec_pdata->srgb_pcc_data.color_tbl); + spec_pdata->srgb_pcc_data.color_tbl = NULL; + pr_err("%s:%d, Unable to read sRGB pcc table", + __func__, __LINE__); + } + } + + spec_pdata->vivid_pcc_enable = of_property_read_bool(np, + "somc,mdss-dsi-vivid-pcc-enable"); + if (spec_pdata->vivid_pcc_enable) { + rc = of_property_read_u32(np, + "somc,mdss-dsi-vivid-pcc-table-size", &tmp); + spec_pdata->vivid_pcc_data.tbl_size = + (!rc ? tmp : 0); + + spec_pdata->vivid_pcc_data.color_tbl = + kzalloc(spec_pdata->vivid_pcc_data.tbl_size * + sizeof(struct mdss_pcc_color_tbl), + GFP_KERNEL); + if (!spec_pdata->vivid_pcc_data.color_tbl) { + pr_err("no mem assigned: kzalloc fail\n"); + return -ENOMEM; + } + rc = of_property_read_u32_array(np, + "somc,mdss-dsi-vivid-pcc-table", + (u32 *)spec_pdata->vivid_pcc_data.color_tbl, + spec_pdata->vivid_pcc_data.tbl_size * + sizeof(struct mdss_pcc_color_tbl) / + sizeof(u32)); + if (rc) { + spec_pdata->vivid_pcc_data.tbl_size = 0; + kzfree(spec_pdata->vivid_pcc_data.color_tbl); + spec_pdata->vivid_pcc_data.color_tbl = NULL; + pr_err("%s:%d, Unable to read Vivid pcc table", + __func__, __LINE__); + } + } + + spec_pdata->hdr_pcc_enable = of_property_read_bool(np, + "somc,mdss-dsi-hdr-pcc-enable"); + if (spec_pdata->hdr_pcc_enable) { + rc = of_property_read_u32(np, + "somc,mdss-dsi-hdr-pcc-table-size", &tmp); + spec_pdata->hdr_pcc_data.tbl_size = + (!rc ? tmp : 0); + + spec_pdata->hdr_pcc_data.color_tbl = + kzalloc(spec_pdata->hdr_pcc_data.tbl_size * + sizeof(struct mdss_pcc_color_tbl), + GFP_KERNEL); + if (!spec_pdata->hdr_pcc_data.color_tbl) { + pr_err("no mem assigned: kzalloc fail\n"); + return -ENOMEM; + } + rc = of_property_read_u32_array(np, + "somc,mdss-dsi-hdr-pcc-table", + (u32 *)spec_pdata->hdr_pcc_data.color_tbl, + spec_pdata->hdr_pcc_data.tbl_size * + sizeof(struct mdss_pcc_color_tbl) / + sizeof(u32)); + if (rc) { + spec_pdata->hdr_pcc_data.tbl_size = 0; + kzfree(spec_pdata->hdr_pcc_data.color_tbl); + spec_pdata->hdr_pcc_data.color_tbl = NULL; + pr_err("%s:%d, Unable to read HDR pcc table", + __func__, __LINE__); + } + } + + (void)mdss_dsi_property_read_u32_var(np, + "somc,pw-on-rst-seq", + (u32 **)&spec_pdata->on_seq.rst_seq, + &spec_pdata->on_seq.seq_num); + + + if (of_find_property(np, "somc,pw-off-rst-b-seq", NULL)) { + spec_pdata->off_seq.rst_b_seq = true; + + (void)mdss_dsi_property_read_u32_var(np, + "somc,pw-off-rst-b-seq", + (u32 **)&spec_pdata->off_seq.rst_seq, + &spec_pdata->off_seq.seq_num); + } else { + (void)mdss_dsi_property_read_u32_var(np, + "somc,pw-off-rst-seq", + (u32 **)&spec_pdata->off_seq.rst_seq, + &spec_pdata->off_seq.seq_num); + } + + + rc = of_property_read_u32(np, + "somc,pw-wait-after-on-vddio", &tmp); + spec_pdata->on_seq.disp_vddio = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-on-vsp", &tmp); + spec_pdata->on_seq.disp_vsp = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-on-vsn", &tmp); + spec_pdata->on_seq.disp_vsn = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-on-dcdc", &tmp); + spec_pdata->on_seq.disp_dcdc = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-off-vddio", &tmp); + spec_pdata->off_seq.disp_vddio = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-off-vsp", &tmp); + spec_pdata->off_seq.disp_vsp = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-off-vsn", &tmp); + spec_pdata->off_seq.disp_vsn = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-off-dcdc", &tmp); + spec_pdata->off_seq.disp_dcdc = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-on-touch-avdd", &tmp); + spec_pdata->on_seq.touch_avdd = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-on-touch-vddio", &tmp); + spec_pdata->on_seq.touch_vddio = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-on-touch-reset", &tmp); + spec_pdata->on_seq.touch_reset = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-on-touch-reset-first", &tmp); + spec_pdata->on_seq.touch_reset_first = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-on-touch-int-n", &tmp); + spec_pdata->on_seq.touch_intn = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-off-touch-avdd", &tmp); + spec_pdata->off_seq.touch_avdd = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-off-touch-vddio", &tmp); + spec_pdata->off_seq.touch_vddio = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-off-touch-reset", &tmp); + spec_pdata->off_seq.touch_reset = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-wait-after-off-touch-int-n", &tmp); + spec_pdata->off_seq.touch_intn = !rc ? tmp : 0; + + rc = of_property_read_u32(np, + "somc,pw-down-period", &tmp); + spec_pdata->down_period = !rc ? tmp : 0; + + rc = mdss_dsi_property_read_u32_var(np, + "somc,ewu-rst-seq", + (u32 **)&spec_pdata->ewu_seq.rst_seq, + &spec_pdata->ewu_seq.seq_num); + if (rc) { + spec_pdata->ewu_seq.rst_seq = NULL; + spec_pdata->ewu_seq.seq_num = 0; + pr_debug("%s: Unable to read ewu sequence\n", __func__); + } + + rc = of_property_read_u32(np, + "somc,ewu-wait-after-touch-reset", &tmp); + spec_pdata->ewu_seq.touch_reset = !rc ? tmp : 0; + + panel_np = of_parse_phandle(np, "qcom,panel-supply-entries", 0); + + panel_type_name = of_node_full_name(panel_np); + if (!strcmp(panel_type_name, NODE_OF_HYBRID)) + spec_pdata->panel_type = HYBRID_INCELL; + if (!strcmp(panel_type_name, NODE_OF_FULL)) + spec_pdata->panel_type = FULL_INCELL; + + panel_np = of_parse_phandle(np, "qcom,panel-supply-entries", 0); + + panel_type_name = of_node_full_name(panel_np); + if (!strcmp(panel_type_name, NODE_OF_HYBRID)) + spec_pdata->panel_type = HYBRID_INCELL; + if (!strcmp(panel_type_name, NODE_OF_FULL)) + spec_pdata->panel_type = FULL_INCELL; + + spec_pdata->chg_fps.enable = of_property_read_bool(np, + "somc,change-fps-enable"); + if (spec_pdata->chg_fps.enable) { + + spec_pdata->input_fpks = pinfo->mipi.frame_rate * 1000; + mdss_dsi_parse_dcs_cmds(np, &spec_pdata->fps_cmds, + "somc,change-fps-command", NULL); + + rc = of_property_read_u32(np, + "somc,driver-ic-vdisp", &tmp); + if (rc) { + pr_err("%s: Display vdisp not specified\n", __func__); + goto error; + } + spec_pdata->chg_fps.dric_vdisp = tmp; + + fps_type = of_get_property(np, + "somc,change-fps-panel-type", NULL); + if (!fps_type) { + pr_err("%s:%d, Panel type not specified\n", + __func__, __LINE__); + goto error; + } + + if (!strncmp(fps_type, "uhd_4k_type", 11)) { + spec_pdata->chg_fps.type = FPS_TYPE_UHD_4K; + } else if (!strncmp(fps_type, "hybrid_incell_type", 18)) { + spec_pdata->chg_fps.type = FPS_TYPE_HYBRID_INCELL; + } else if (!strncmp(fps_type, "full_incell_type", 16)) { + spec_pdata->chg_fps.type = FPS_TYPE_FULL_INCELL; + } else { + pr_err("%s: Unable to read fps panel type\n", __func__); + goto error; + } + + fps_mode = of_get_property(np, + "somc,change-fps-panel-mode", NULL); + if (!fps_mode) { + pr_err("%s:%d, Panel mode not specified\n", + __func__, __LINE__); + goto error; + } + + if (!strncmp(fps_mode, "susres_mode", 11)) { + spec_pdata->chg_fps.mode = FPS_MODE_SUSRES; + } else if (!strncmp(fps_mode, "dynamic_mode", 12)) { + spec_pdata->chg_fps.mode = FPS_MODE_DYNAMIC; + } else { + pr_err("%s: Unable to read fps panel mode\n", __func__); + goto error; + } + + switch (spec_pdata->chg_fps.type) { + case FPS_TYPE_UHD_4K: + (void)mdss_dsi_property_read_u32_var(np, + "somc,change-fps-rtn-pos", + (u32 **)&spec_pdata->chg_fps.send_pos.pos, + &spec_pdata->chg_fps.send_pos.num); + + rc = of_property_read_u32(np, + "somc,driver-ic-total-porch", &tmp); + if (rc) { + pr_err("%s: DrIC total_porch not specified\n", + __func__); + goto error; + } + spec_pdata->chg_fps.dric_total_porch = tmp; + + rc = of_property_read_u32(np, + "somc,driver-ic-rclk", &tmp); + if (rc) { + pr_err("%s: DrIC rclk not specified\n", + __func__); + goto error; + } + spec_pdata->chg_fps.dric_rclk = tmp; + + spec_pdata->chg_fps.rtn_adj = of_property_read_bool(np, + "somc,change-fps-rtn-adj"); + break; + case FPS_TYPE_HYBRID_INCELL: + (void)mdss_dsi_property_read_u32_var(np, + "somc,change-fps-send-pos", + (u32 **)&spec_pdata->chg_fps.send_pos.pos, + &spec_pdata->chg_fps.send_pos.num); + + rc = of_property_read_u32(np, + "somc,driver-ic-rtn", &tmp); + if (rc) { + pr_err("%s: DrIC rtn not specified\n", + __func__); + goto error; + } + spec_pdata->chg_fps.dric_rtn = tmp; + + (void)mdss_dsi_property_read_u32_var(np, + "somc,change-fps-send-pos", + (u32 **)&spec_pdata->chg_fps.send_pos.pos, + &spec_pdata->chg_fps.send_pos.num); + + rc = of_property_read_u32(np, + "somc,driver-ic-mclk", &tmp); + if (rc) { + pr_err("%s: DrIC mclk not specified\n", + __func__); + goto error; + } + spec_pdata->chg_fps.dric_mclk = tmp; + + rc = of_property_read_u32(np, + "somc,driver-ic-vtouch", &tmp); + if (rc) { + pr_err("%s: DrIC vtouch not specified\n", + __func__); + goto error; + } + spec_pdata->chg_fps.dric_vtouch = tmp; + + rc = of_property_read_u32(np, + "somc,change-fps-send-byte", &tmp); + if (rc) { + pr_err("%s: fps bytes send not specified\n", + __func__); + goto error; + } + spec_pdata->chg_fps.send_byte = tmp; + + rc = of_property_read_u32(np, + "somc,change-fps-porch-mask-pos", &tmp); + if (rc) { + pr_warn("%s: fps mask position not specified\n", + __func__); + spec_pdata->chg_fps.mask_pos = 0; + } else { + spec_pdata->chg_fps.mask_pos = tmp; + rc = of_property_read_u32(np, + "somc,change-fps-porch-mask", &tmp); + if (rc) { + pr_warn("%s: fps mask not specified\n", + __func__); + spec_pdata->chg_fps.mask = 0x0; + } else { + spec_pdata->chg_fps.mask = tmp; + } + } + + rc = of_property_read_u32_array(np, + "somc,change-fps-porch-range", + spec_pdata->chg_fps.porch_range, + FPS_PORCH_RNG_NUM); + if (rc) { + spec_pdata->chg_fps.porch_range[FPS_PORCH_RNG_MIN] = 0; + spec_pdata->chg_fps.porch_range[FPS_PORCH_RNG_MAX] = 0; + } + break; + case FPS_TYPE_FULL_INCELL: + (void)mdss_dsi_property_read_u32_var(np, + "somc,change-fps-rtn-pos", + (u32 **)&spec_pdata->chg_fps.send_pos.pos, + &spec_pdata->chg_fps.send_pos.num); + + rc = of_property_read_u32(np, + "somc,driver-ic-total-porch", &tmp); + if (rc) { + pr_err("%s: DrIC total_porch not specified\n", + __func__); + goto error; + } + spec_pdata->chg_fps.dric_total_porch = tmp; + + rc = of_property_read_u32(np, + "somc,driver-ic-rclk", &tmp); + if (rc) { + pr_err("%s: DrIC rclk not specified\n", + __func__); + goto error; + } + spec_pdata->chg_fps.dric_rclk = tmp; + + rc = of_property_read_u32(np, + "somc,driver-ic-vtp", &tmp); + if (rc) { + pr_err("%s: DrIC vtp not specified\n", + __func__); + goto error; + } + spec_pdata->chg_fps.dric_tp = tmp; + break; + default: + pr_err("%s: Read panel mode failed.\n", __func__); + goto error; + } + } + + /* Parsing lab/ibb register settings */ + labibb = &spec_pdata->labibb; + + memset(labibb, 0, sizeof(*labibb)); + if (of_find_property(np, "somc,lab-output-voltage", &tmp)) + labibb->labibb_ctrl_state |= OVR_LAB_VOLTAGE; + + if (of_find_property(np, "somc,ibb-output-voltage", &tmp)) + labibb->labibb_ctrl_state |= OVR_IBB_VOLTAGE; + + if (of_find_property(np, "somc,qpnp-lab-limit-maximum-current", &tmp)) + labibb->labibb_ctrl_state |= OVR_LAB_CURRENT_MAX; + + if (of_find_property(np, "somc,qpnp-ibb-limit-maximum-current", &tmp)) + labibb->labibb_ctrl_state |= OVR_IBB_CURRENT_MAX; + + if (of_find_property(np, "somc,qpnp-lab-max-precharge-time", &tmp)) + labibb->labibb_ctrl_state |= OVR_LAB_PRECHARGE_CTL; + + if (of_find_property(np, "somc,qpnp-lab-soft-start", &tmp)) + labibb->labibb_ctrl_state |= OVR_LAB_SOFT_START_CTL; + + if (of_find_property(np, "somc,qpnp-ibb-discharge-resistor", &tmp)) + labibb->labibb_ctrl_state |= OVR_IBB_SOFT_START_CTL; + + if (of_find_property(np, "somc,qpnp-lab-pull-down-enable", &tmp)) + labibb->labibb_ctrl_state |= OVR_LAB_PD_CTL; + + if (of_find_property(np, "somc,qpnp-ibb-pull-down-enable", &tmp)) + labibb->labibb_ctrl_state |= OVR_IBB_PD_CTL; + + labibb->lab_output_voltage = QPNP_REGULATOR_VSP_V_5P4V; + if (((labibb->labibb_ctrl_state) & OVR_LAB_VOLTAGE)) { + rc = of_property_read_u32(np, "somc,lab-output-voltage", &tmp); + if (!rc) + labibb->lab_output_voltage = tmp; + } + + labibb->ibb_output_voltage = QPNP_REGULATOR_VSN_V_M5P4V; + if (((labibb->labibb_ctrl_state) & OVR_IBB_VOLTAGE)) { + rc = of_property_read_u32(np, "somc,ibb-output-voltage", &tmp); + if (!rc) + labibb->ibb_output_voltage = tmp; + } + + labibb->lab_current_max = LAB_CURRENT_MAX; + if (((labibb->labibb_ctrl_state) & OVR_LAB_CURRENT_MAX)) { + rc = of_property_read_u32(np, + "somc,qpnp-lab-limit-maximum-current", &tmp); + if (!rc) + labibb->lab_current_max = tmp; + } + + labibb->ibb_current_max = IBB_CURRENT_MAX; + if (((labibb->labibb_ctrl_state) & OVR_IBB_CURRENT_MAX)) { + rc = of_property_read_u32(np, + "somc,qpnp-ibb-limit-maximum-current", &tmp); + if (!rc) + labibb->ibb_current_max = tmp; + } + + labibb->lab_fast_precharge_time = LAB_FAST_PRECHARGE_TIME; + labibb->lab_fast_precharge_en = false; + if (((labibb->labibb_ctrl_state) & OVR_LAB_PRECHARGE_CTL)) { + rc = of_property_read_u32(np, + "somc,qpnp-lab-max-precharge-time", &tmp); + if (!rc) + labibb->lab_fast_precharge_time = tmp; + + labibb->lab_fast_precharge_en = of_property_read_bool(np, + "somc,qpnp-lab-max-precharge-enable"); + } + + labibb->lab_soft_start = LAB_SOFT_START_TIME; + if (((labibb->labibb_ctrl_state) & OVR_LAB_SOFT_START_CTL)) { + rc = of_property_read_u32(np, + "somc,qpnp-lab-soft-start", &tmp); + if (!rc) + labibb->lab_soft_start = tmp; + } + + labibb->ibb_soft_start = IBB_SOFT_START_RESISTOR; + if (((labibb->labibb_ctrl_state) & OVR_IBB_SOFT_START_CTL)) { + rc = of_property_read_u32(np, + "somc,qpnp-ibb-discharge-resistor", &tmp); + if (!rc) + labibb->ibb_soft_start = tmp; + } + + labibb->lab_pd_full = false; + if (((labibb->labibb_ctrl_state) & OVR_LAB_PD_CTL)) + labibb->lab_pd_full = of_property_read_bool(np, + "somc,qpnp-lab-full-pull-down"); + + labibb->ibb_pd_full = false; + if (((labibb->labibb_ctrl_state) & OVR_IBB_PD_CTL)) + labibb->ibb_pd_full = of_property_read_bool(np, + "somc,qpnp-ibb-full-pull-down"); + + return 0; + +error: + return -EINVAL; +} + +static void conv_uv_data(char *data, int param_type, int *u_data, int *v_data) +{ + switch (param_type) { + case CLR_DATA_UV_PARAM_TYPE_RENE_DEFAULT: + *u_data = ((data[0] & 0x0F) << 2) | + /* 4bit of data[0] higher data. */ + ((data[1] >> 6) & 0x03); + /* 2bit of data[1] lower data. */ + *v_data = (data[1] & 0x3F); + /* Remainder 6bit of data[1] is effective as v_data. */ + break; + case CLR_DATA_UV_PARAM_TYPE_NOVA_DEFAULT: + case CLR_DATA_UV_PARAM_TYPE_RENE_SR: + /* 6bit is effective as u_data */ + *u_data = data[0] & 0x3F; + /* 6bit is effective as v_data */ + *v_data = data[1] & 0x3F; + break; + case CLR_DATA_UV_PARAM_TYPE_NOVA_AUO: + /* 6bit is effective as u_data */ + *u_data = data[0] & 0x3F; + /* 6bit is effective as v_data */ + *v_data = data[2] & 0x3F; + break; + default: + pr_err("%s: Failed to conv type:%d\n", __func__, param_type); + break; + } +} + +static int get_uv_param_len(int param_type, bool *short_response) +{ + int ret = 0; + + *short_response = false; + switch (param_type) { + case CLR_DATA_UV_PARAM_TYPE_RENE_DEFAULT: + ret = CLR_DATA_REG_LEN_RENE_DEFAULT; + break; + case CLR_DATA_UV_PARAM_TYPE_NOVA_DEFAULT: + ret = CLR_DATA_REG_LEN_NOVA_DEFAULT; + break; + case CLR_DATA_UV_PARAM_TYPE_NOVA_AUO: + ret = CLR_DATA_REG_LEN_NOVA_AUO; + break; + case CLR_DATA_UV_PARAM_TYPE_RENE_SR: + ret = CLR_DATA_REG_LEN_RENE_SR; + *short_response = true; + break; + default: + pr_err("%s: Failed to get param len\n", __func__); + break; + } + + return ret; +} + +static void get_uv_data(struct mdss_dsi_ctrl_pdata *ctrl_pdata, + int *u_data, int *v_data) +{ + struct dsi_cmd_desc *cmds = ctrl_pdata->spec_pdata->uv_read_cmds.cmds; + int param_type = ctrl_pdata->spec_pdata->pcc_data.param_type; + char buf[MDSS_DSI_LEN]; + char *pos = buf; + int len; + int i; + bool short_response; + struct dcs_cmd_req cmdreq; + + len = get_uv_param_len(param_type, &short_response); + + for (i = 0; i < ctrl_pdata->spec_pdata->uv_read_cmds.cmd_cnt; i++) { + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds = cmds; + cmdreq.cmds_cnt = 1; + cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT; + cmdreq.rlen = short_response ? 1 : len; + cmdreq.rbuf = ctrl_pdata->rx_buf.data; + cmdreq.cb = NULL; + + mdss_dsi_cmdlist_put(ctrl_pdata, &cmdreq); + + memcpy(pos, ctrl_pdata->rx_buf.data, len); + pos += len; + cmds++; + } + conv_uv_data(buf, param_type, u_data, v_data); +} + +static int find_color_area(struct mdp_pcc_cfg_data *pcc_config, + struct mdss_pcc_data *pcc_data) +{ + int i; + int ret = 0; + + for (i = 0; i < pcc_data->tbl_size; i++) { + if (pcc_data->u_data < pcc_data->color_tbl[i].u_min) + continue; + if (pcc_data->u_data > pcc_data->color_tbl[i].u_max) + continue; + if (pcc_data->v_data < pcc_data->color_tbl[i].v_min) + continue; + if (pcc_data->v_data > pcc_data->color_tbl[i].v_max) + continue; + break; + } + pcc_data->tbl_idx = i; + if (i >= pcc_data->tbl_size) { + ret = -EINVAL; + goto exit; + } + + pcc_config->r.r = pcc_data->color_tbl[i].r_data; + pcc_config->g.g = pcc_data->color_tbl[i].g_data; + pcc_config->b.b = pcc_data->color_tbl[i].b_data; +exit: + return ret; +} + +static int find_color_area_for_srgb(struct mdss_pcc_data *pcc_data) +{ + int i; + int ret = 0; + + for (i = 0; i < pcc_data->tbl_size; i++) { + if (pcc_data->u_data < pcc_data->color_tbl[i].u_min) + continue; + if (pcc_data->u_data > pcc_data->color_tbl[i].u_max) + continue; + if (pcc_data->v_data < pcc_data->color_tbl[i].v_min) + continue; + if (pcc_data->v_data > pcc_data->color_tbl[i].v_max) + continue; + break; + } + pcc_data->tbl_idx = i; + if (i >= pcc_data->tbl_size) { + ret = -EINVAL; + } + + return ret; +} + +static int find_color_area_for_vivid(struct mdss_pcc_data *pcc_data) +{ + return find_color_area_for_srgb(pcc_data); +} + +static int find_color_area_for_hdr(struct mdss_pcc_data *pcc_data) +{ + return find_color_area_for_srgb(pcc_data); +} + +int mdss_dsi_panel_pcc_setup(struct mdss_panel_data *pdata) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_pcc_data *pcc_data = NULL; + struct mdss_pcc_data *srgb_pcc_data = NULL; + struct mdss_pcc_data *vivid_pcc_data = NULL; + struct mdss_pcc_data *hdr_pcc_data = NULL; + struct mdp_pcc_cfg_data pcc_config; + int ret; + u32 raw_u_data = 0, raw_v_data = 0; + struct mdss_panel_specific_pdata *spec_pdata = NULL; + u8 idx = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + spec_pdata = ctrl_pdata->spec_pdata; + + if (!ctrl_pdata->spec_pdata->pcc_enable) { + if (pdata->panel_info.dsi_master == pdata->panel_info.pdest) + pr_notice("%s (%d): pcc isn't enabled.\n", + __func__, __LINE__); + goto exit; + } + + pcc_data = &ctrl_pdata->spec_pdata->pcc_data; + + mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata); + if (ctrl_pdata->spec_pdata->pre_uv_read_cmds.cmds) + mdss_dsi_panel_cmds_send( + ctrl_pdata, &ctrl_pdata->spec_pdata->pre_uv_read_cmds, CMD_REQ_COMMIT); + if (ctrl_pdata->spec_pdata->uv_read_cmds.cmds) { + get_uv_data(ctrl_pdata, &pcc_data->u_data, &pcc_data->v_data); + raw_u_data = pcc_data->u_data; + raw_v_data = pcc_data->v_data; + } + if (pcc_data->u_data == 0 && pcc_data->v_data == 0) { + pr_notice("%s (%d): u,v is flashed 0.\n", + __func__, __LINE__); + goto exit; + } + if (!pcc_data->color_tbl) { + if (pdata->panel_info.dsi_master == pdata->panel_info.pdest) + pr_notice("%s (%d): color_tbl isn't found.\n", + __func__, __LINE__); + goto exit; + } + + memset(&pcc_config, 0, sizeof(struct mdp_pcc_cfg_data)); + ret = find_color_area(&pcc_config, pcc_data); + if (ret) { + pr_err("%s: failed to find color area.\n", __func__); + goto exit; + } + + if (spec_pdata->srgb_pcc_enable) { + srgb_pcc_data = &spec_pdata->srgb_pcc_data; + srgb_pcc_data->u_data = pcc_data->u_data; + srgb_pcc_data->v_data = pcc_data->v_data; + ret = find_color_area_for_srgb(srgb_pcc_data); + if (ret) { + pr_err("%s: failed to find color area.\n", __func__); + goto exit; + } + idx = srgb_pcc_data->tbl_idx; + pr_notice("SRGB : %s (%d): raw_ud=%d raw_vd=%d ct=%d " + "area=%d ud=%d vd=%d r=0x%08X g=0x%08X b=0x%08X\n", + __func__, __LINE__, + raw_u_data, raw_v_data, + srgb_pcc_data->color_tbl[idx].color_type, + srgb_pcc_data->color_tbl[idx].area_num, + srgb_pcc_data->u_data, srgb_pcc_data->v_data, + srgb_pcc_data->color_tbl[idx].r_data, + srgb_pcc_data->color_tbl[idx].g_data, + srgb_pcc_data->color_tbl[idx].b_data); + } + + if (spec_pdata->vivid_pcc_enable) { + vivid_pcc_data = &spec_pdata->vivid_pcc_data; + vivid_pcc_data->u_data = pcc_data->u_data; + vivid_pcc_data->v_data = pcc_data->v_data; + ret = find_color_area_for_vivid(vivid_pcc_data); + if (ret) { + pr_err("%s: failed to find color area.\n", __func__); + goto exit; + } + idx = vivid_pcc_data->tbl_idx; + pr_notice("Vivid : %s (%d): raw_ud=%d raw_vd=%d ct=%d " + "area=%d ud=%d vd=%d r=0x%08X g=0x%08X b=0x%08X\n", + __func__, __LINE__, + raw_u_data, raw_v_data, + vivid_pcc_data->color_tbl[idx].color_type, + vivid_pcc_data->color_tbl[idx].area_num, + vivid_pcc_data->u_data, vivid_pcc_data->v_data, + vivid_pcc_data->color_tbl[idx].r_data, + vivid_pcc_data->color_tbl[idx].g_data, + vivid_pcc_data->color_tbl[idx].b_data); + } + + if (spec_pdata->hdr_pcc_enable) { + hdr_pcc_data = &spec_pdata->hdr_pcc_data; + hdr_pcc_data->u_data = pcc_data->u_data; + hdr_pcc_data->v_data = pcc_data->v_data; + ret = find_color_area_for_hdr(hdr_pcc_data); + if (ret) { + pr_err("%s: failed to find color area.\n", __func__); + goto exit; + } + idx = hdr_pcc_data->tbl_idx; + pr_notice("HDR : %s (%d): raw_ud=%d raw_vd=%d ct=%d " + "area=%d ud=%d vd=%d r=0x%08X g=0x%08X b=0x%08X\n", + __func__, __LINE__, + raw_u_data, raw_v_data, + hdr_pcc_data->color_tbl[idx].color_type, + hdr_pcc_data->color_tbl[idx].area_num, + hdr_pcc_data->u_data, hdr_pcc_data->v_data, + hdr_pcc_data->color_tbl[idx].r_data, + hdr_pcc_data->color_tbl[idx].g_data, + hdr_pcc_data->color_tbl[idx].b_data); + } + + pr_notice("%s (%d): raw_ud=%d raw_vd=%d " + "ct=%d area=%d ud=%d vd=%d r=0x%08X g=0x%08X b=0x%08X\n", + __func__, __LINE__, + raw_u_data, raw_v_data, + pcc_data->color_tbl[pcc_data->tbl_idx].color_type, + pcc_data->color_tbl[pcc_data->tbl_idx].area_num, + pcc_data->u_data, pcc_data->v_data, + pcc_data->color_tbl[pcc_data->tbl_idx].r_data, + pcc_data->color_tbl[pcc_data->tbl_idx].g_data, + pcc_data->color_tbl[pcc_data->tbl_idx].b_data); + +exit: + return 0; +} + +struct mdss_panel_specific_pdata *mdss_panel2spec_pdata( + struct mdss_panel_data *pdata) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata; + + ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); + return ctrl_pdata->spec_pdata; +} + +static u32 ts_diff_ms(struct timespec lhs, struct timespec rhs) +{ + struct timespec tdiff; + s64 nsec; + u32 msec; + + tdiff = timespec_sub(lhs, rhs); + nsec = timespec_to_ns(&tdiff); + msec = (u32)nsec; + do_div(msec, NSEC_PER_MSEC); + + return msec; +} + +static struct fps_data *mdss_dsi_panel_driver_get_fps_address(fps_type type) +{ + switch (type) { + case FPSD: + return &fpsd; + case VPSD: + return &vpsd; + default: + pr_err("%s: select Failed!\n", __func__); + return NULL; + } +} + +static void update_fps_data(struct fps_data *fps) +{ + if (mutex_trylock(&fps->fps_lock)) { + u32 fpks = 0; + u32 ms_since_last = 0; + u32 num_frames; + struct timespec tlast = fps->timestamp_last; + struct timespec tnow; + u32 msec; + + getrawmonotonic(&tnow); + msec = ts_diff_ms(tnow, tlast); + fps->timestamp_last = tnow; + + fps->interval_ms = msec; + fps->frame_counter++; + num_frames = fps->frame_counter - fps->frame_counter_last; + + fps->fa[fps->fps_array_cnt].frame_nbr = fps->frame_counter; + fps->fa[fps->fps_array_cnt].time_delta = msec; + fps->fa_last_array_pos = fps->fps_array_cnt; + (fps->fps_array_cnt)++; + if (fps->fps_array_cnt >= DEFAULT_FPS_ARRAY_SIZE) + fps->fps_array_cnt = 0; + + ms_since_last = ts_diff_ms(tnow, fps->fpks_ts_last); + + if (num_frames > 1 && ms_since_last >= fps->log_interval) { + fpks = (num_frames * 1000000) / ms_since_last; + fps->fpks_ts_last = tnow; + fps->frame_counter_last = fps->frame_counter; + fps->fpks = fpks; + } + mutex_unlock(&fps->fps_lock); + } +} + +static void mdss_dsi_panel_driver_fps_data_init(fps_type type) +{ + struct fps_data *fps = mdss_dsi_panel_driver_get_fps_address(type); + + if (!fps) { + pr_err("%s: select Failed!\n", __func__); + return; + } + + fps->frame_counter = 0; + fps->frame_counter_last = 0; + fps->log_interval = DEFAULT_FPS_LOG_INTERVAL; + fps->fpks = 0; + fps->fa_last_array_pos = 0; + fps->vps_en = false; + getrawmonotonic(&fps->timestamp_last); + mutex_init(&fps->fps_lock); +} + +void mdss_dsi_panel_driver_fps_data_update( + struct msm_fb_data_type *mfd, fps_type type) +{ + struct fps_data *fps = mdss_dsi_panel_driver_get_fps_address(type); + + if (!fps) { + pr_err("%s: select Failed!\n", __func__); + return; + } + + if (mfd->index == 0) + update_fps_data(fps); +} + +struct fps_data mdss_dsi_panel_driver_get_fps_data(void) +{ + return fpsd; +} + +struct fps_data mdss_dsi_panel_driver_get_vps_data(void) +{ + return vpsd; +} + +static void vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t) +{ + struct msm_fb_data_type *mfd = ctl->mfd; + + mdss_dsi_panel_driver_fps_data_update(mfd, VPSD); +} + +static void mdss_dsi_panel_driver_vsync_handler_init(void) +{ + vs_handle.vsync_handler = NULL; +} + +ssize_t mdss_dsi_panel_driver_vsyncs_per_ksecs_store(struct device *dev, + const char *buf, size_t count) +{ + int ret = count; + long vps_en; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_ctl *ctl = mdata->ctl_off; + + if (kstrtol(buf, 10, &vps_en)) { + dev_err(dev, "%s: Error, buf = %s\n", __func__, buf); + ret = -EINVAL; + goto exit; + } + + vs_handle.vsync_handler = (mdp_vsync_handler_t)vsync_handler; + vs_handle.cmd_post_flush = false; + + if (vps_en) { + vs_handle.enabled = false; + if (!vpsd.vps_en && (ctl->ops.add_vsync_handler)) { + ctl->ops.add_vsync_handler(ctl, &vs_handle); + vpsd.vps_en = true; + pr_notice("%s: vsyncs_per_ksecs is valid\n", __func__); + } + } else { + vs_handle.enabled = true; + if (vpsd.vps_en && (ctl->ops.remove_vsync_handler)) { + ctl->ops.remove_vsync_handler(ctl, &vs_handle); + vpsd.vps_en = false; + fpsd.fpks = 0; + pr_notice("%s: vsyncs_per_ksecs is invalid\n", __func__); + } + } +exit: + return ret; +} + +static void mdss_dsi_panel_driver_fps_cmd_send( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, + u32 dfpks_rev, int dfpks) { + char dfps = (char)(dfpks_rev / KSEC); + struct mdss_panel_specific_pdata *spec_pdata = ctrl_pdata->spec_pdata; + struct mdss_panel_info *pinfo = &ctrl_pdata->panel_data.panel_info; + + pinfo->mipi.frame_rate = dfps; + + if (spec_pdata->chg_fps.mode != FPS_MODE_SUSRES) { + pr_debug("%s: fps change sequence\n", __func__); + mdss_dsi_panel_cmds_send(ctrl_pdata, + &ctrl_pdata->spec_pdata->fps_cmds, + CMD_REQ_COMMIT); + } + pr_notice("%s: change fpks=%d\n", __func__, dfpks); + + pinfo->new_fps = dfps; + spec_pdata->input_fpks = dfpks; +} + +static int mdss_dsi_panel_driver_fps_calc_rtn( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, int dfpks) { + u32 dfpks_rev; + u32 vtotal_porch, vdisp; + u32 vrclk, vtp; + u32 cmds, payload; + struct mdss_panel_specific_pdata *spec_pdata = ctrl_pdata->spec_pdata; + u16 rtn; + int i, j, byte_cnt; + char send_rtn[sizeof(u16)] = {0}; + + vtotal_porch = spec_pdata->chg_fps.dric_total_porch; + vdisp = spec_pdata->chg_fps.dric_vdisp; + + vrclk = spec_pdata->chg_fps.dric_rclk; + vtp = spec_pdata->chg_fps.dric_tp; + + if (!dfpks || !(vdisp + vtotal_porch + vtp)) { + pr_err("%s: Invalid param dfpks=%d vdisp=%d porch=%d vtp=%d\n", + __func__, dfpks, vdisp, vtotal_porch, vtp); + return -EINVAL; + } + + rtn = (u16)( + (vrclk * KSEC) / + (dfpks * (vdisp + vtotal_porch + vtp)) + ); + + if (!rtn || !(vdisp + vtotal_porch + vtp)) { + pr_err("%s: Invalid param rtn=%d vdisp=%d porch=%d vtp=%d\n", + __func__, dfpks, vdisp, vtotal_porch, vtp); + return -EINVAL; + } + + dfpks_rev = (u32)( + (vrclk * KSEC) / + (rtn * (vdisp + vtotal_porch + vtp)) + ); + + pr_debug("%s: porch=%d vdisp=%d vtp=%d vrclk=%d rtn=0x%x\n", + __func__, vtotal_porch, vdisp, vtp, vrclk, rtn); + + for (i = 0; i < sizeof(send_rtn) ; i++) { + send_rtn[i] = (char)(rtn & 0x00FF); + pr_debug("%s: send_rtn[%d]=0x%x\n", + __func__, i, send_rtn[i]); + if (rtn > 0xFF) { + rtn = (rtn >> 8); + } else { + byte_cnt = i; + break; + } + } + + for (i = 0; i < (spec_pdata->chg_fps.send_pos.num / 2); i++) { + cmds = spec_pdata->chg_fps.send_pos.pos[(i * 2)]; + payload = spec_pdata->chg_fps.send_pos.pos[(i * 2) + 1]; + for (j = 0; j <= byte_cnt ; j++) + CHANGE_PAYLOAD(cmds, payload + j) = + send_rtn[byte_cnt - j]; + } + + mdss_dsi_panel_driver_fps_cmd_send(ctrl_pdata, dfpks_rev, dfpks); + + return 0; +} + +static int mdss_dsi_panel_driver_fps_calc_porch + (struct mdss_dsi_ctrl_pdata *ctrl_pdata, int dfpks) { + u64 vmclk; + u64 vtouch; + u32 dfpks_rev; + u32 vdisp; + u32 cmds, payload; + u32 porch_range_max = 0; + u32 porch_range_min = 0; + + int i, j; + u16 porch_calc = 0; + u16 send_byte; + u16 rtn; + u8 mask_pos; + char mask; + char porch[CHANGE_FPS_PORCH] = {0}; + char send[CHANGE_FPS_SEND] = {0}; + struct mdss_panel_specific_pdata *spec_pdata = ctrl_pdata->spec_pdata; + struct dsi_panel_cmds *fps_cmds = &(spec_pdata->fps_cmds); + + rtn = spec_pdata->chg_fps.dric_rtn; + vdisp = spec_pdata->chg_fps.dric_vdisp; + vtouch = spec_pdata->chg_fps.dric_vtouch; + vmclk = (u64)spec_pdata->chg_fps.dric_mclk; + send_byte = spec_pdata->chg_fps.send_byte; + mask_pos = spec_pdata->chg_fps.mask_pos; + mask = spec_pdata->chg_fps.mask; + porch_range_max = spec_pdata->chg_fps.porch_range[FPS_PORCH_RNG_MAX]; + porch_range_min = spec_pdata->chg_fps.porch_range[FPS_PORCH_RNG_MIN]; + + if (!dfpks || !vmclk || !rtn) { + pr_err("%s: Invalid param dfpks=%d vmclk=%llu rtn%d\n", + __func__, dfpks, vmclk, rtn); + return -EINVAL; + } + + porch_calc = (u16)(( + (((PSEC * KSEC) - (KSEC * vtouch * (u64)dfpks)) / + ((u64)dfpks * vmclk * (u64)rtn)) - (u64)vdisp) / 2); + + if (porch_range_max > 0) { + if ((porch_calc < porch_range_min) + || (porch_calc > porch_range_max)) { + pr_err("%s: Not supported. porch:%d\n", + __func__, porch_calc); + return -EINVAL; + } + } + + if (!(vmclk * rtn * (vdisp + porch_calc) + vtouch)) { + pr_err("%s: Invalid param \ + vmclk=%llu rtn=%d vdisp=%d porch=%d vtouch=%llu\n", + __func__, vmclk, rtn, vdisp, porch_calc, vtouch); + return -EINVAL; + } + + dfpks_rev = (u32)( + (PSEC * KSEC) / + (vmclk * rtn * (vdisp + porch_calc) + vtouch)); + + pr_debug("%s: porch=%d vdisp=%d vtouch=%llu vmclk=%llu rtn=0x%x\n", + __func__, porch_calc, vdisp, vtouch, vmclk, rtn); + + for (i = 0; i < CHANGE_FPS_PORCH ; i++) { + porch[i] = (char)(porch_calc & 0x00FF); + pr_debug("%s: porch[%d]=0x%x\n", __func__, i, porch[i]); + porch_calc = (porch_calc >> 8); + } + + for (i = 0; i < send_byte; i = i + 2) { + memcpy(send + i, porch, sizeof(char)); + memcpy(send + i + 1, porch + 1, sizeof(char)); + } + + for (i = 0; i < (spec_pdata->chg_fps.send_pos.num / 2); i++) { + cmds = spec_pdata->chg_fps.send_pos.pos[(i * 2)]; + payload = spec_pdata->chg_fps.send_pos.pos[(i * 2) + 1]; + for (j = 0; j < send_byte ; j++) { + if (j == mask_pos) + send[j] = (mask | send[j]); + CHANGE_PAYLOAD(cmds, payload + j) = send[j]; + pr_debug("%s: fps_cmds.cmds[%d].payload[%d]) = 0x%x\n", + __func__, + cmds, payload + j, + fps_cmds->cmds[cmds].payload[payload + j]); + } + } + + mdss_dsi_panel_driver_fps_cmd_send(ctrl_pdata, dfpks_rev, dfpks); + + return 0; +} + +static int mdss_dsi_panel_driver_fps_calc_adj + (struct mdss_dsi_ctrl_pdata *ctrl_pdata, int dfpks) { + u32 dfpks_rev; + u32 vtotal_porch, vdisp, vrclk; + u32 cmds, payload; + struct mdss_panel_specific_pdata *spec_pdata = ctrl_pdata->spec_pdata; + u16 rtn; + int i, j, byte_cnt; + char send_rtn[sizeof(u16)] = {0}, adj; + + if (!spec_pdata) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + vtotal_porch = spec_pdata->chg_fps.dric_total_porch; + vdisp = spec_pdata->chg_fps.dric_vdisp; + vrclk = spec_pdata->chg_fps.dric_rclk; + adj = spec_pdata->chg_fps.rtn_adj ? 1 : 0; + + if (!dfpks || !(vdisp + vtotal_porch)) { + pr_err("%s: Invalid param dfpks=%d vdisp=%d porch=%d\n", + __func__, dfpks, vdisp, vtotal_porch); + return -EINVAL; + } + + rtn = (u16)(vrclk / (dfpks * (vdisp + vtotal_porch) / 1000)) - adj; + + if (!rtn || !(vdisp + vtotal_porch)) { + pr_err("%s: Invalid param rtn=%d vdisp=%d porch=%d\n", + __func__, rtn, vdisp, vtotal_porch); + return -EINVAL; + } + + dfpks_rev = (u32)(vrclk / (rtn * (vdisp + vtotal_porch) / 1000)); + + pr_debug("%s: porch=%d vdisp=%d vrclk=%d rtn=0x%x adj=%d\n", + __func__, vtotal_porch, vdisp, vrclk, rtn + adj, adj); + + for (i = 0; i < sizeof(send_rtn) ; i++) { + send_rtn[i] = (char)(rtn & 0x00FF); + pr_debug("%s: send_rtn[%d]=0x%x\n", + __func__, i, send_rtn[i]); + if (rtn > 0xFF) { + rtn = (rtn >> 8); + } else { + byte_cnt = i; + break; + } + } + + for (i = 0; i < (spec_pdata->chg_fps.send_pos.num / 2); i++) { + cmds = spec_pdata->chg_fps.send_pos.pos[(i * 2)]; + payload = spec_pdata->chg_fps.send_pos.pos[(i * 2) + 1]; + for (j = 0; j <= byte_cnt ; j++) + CHANGE_PAYLOAD(cmds, payload + j) = + send_rtn[byte_cnt - j]; + } + + mdss_dsi_panel_driver_fps_cmd_send(ctrl_pdata, dfpks_rev, dfpks); + + return 0; +} + +static int mdss_dsi_panel_chg_fps_calc + (struct mdss_dsi_ctrl_pdata *ctrl_pdata, int dfpks) { + int ret = -EINVAL; + struct mdss_panel_specific_pdata *spec_pdata = NULL; + + spec_pdata = ctrl_pdata->spec_pdata; + if (!spec_pdata) { + pr_err("%s: Invalid input data\n", __func__); + return ret; + } + + switch (spec_pdata->chg_fps.type) { + case FPS_TYPE_UHD_4K: + ret = mdss_dsi_panel_driver_fps_calc_adj(ctrl_pdata, dfpks); + break; + case FPS_TYPE_HYBRID_INCELL: + ret = mdss_dsi_panel_driver_fps_calc_porch(ctrl_pdata, dfpks); + break; + case FPS_TYPE_FULL_INCELL: + ret = mdss_dsi_panel_driver_fps_calc_rtn(ctrl_pdata, dfpks); + break; + default: + pr_err("%s: Invalid type data\n", __func__); + break; + } + + return ret; +} + +static int mdss_dsi_panel_chg_fps_check_state + (struct mdss_dsi_ctrl_pdata *ctrl, int dfpks) { + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct msm_fb_data_type *mfd = mdata->ctl_off->mfd; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; + struct mdss_dsi_ctrl_pdata *sctrl = NULL; + int rc = 0; + + if (!mdp5_data->ctl || !mdp5_data->ctl->power_state) + goto error; + + if ((pinfo->mipi.mode == DSI_CMD_MODE) && + (!ctrl->spec_pdata->fps_cmds.cmd_cnt)) + goto cmd_cnt_err; + + if (!display_onoff_state) + goto disp_onoff_state_err; + + if (mdss_dsi_sync_wait_enable(ctrl)) { + sctrl = mdss_dsi_get_other_ctrl(ctrl); + if (sctrl) { + if (mdss_dsi_sync_wait_trigger(ctrl)) { + rc = mdss_dsi_panel_chg_fps_calc(sctrl, dfpks); + if (rc < 0) + goto end; + rc = mdss_dsi_panel_chg_fps_calc(ctrl, dfpks); + } else { + rc = mdss_dsi_panel_chg_fps_calc(ctrl, dfpks); + if (rc < 0) + goto end; + rc = mdss_dsi_panel_chg_fps_calc(sctrl, dfpks); + } + } else { + rc = mdss_dsi_panel_chg_fps_calc(ctrl, dfpks); + } + } else { + rc = mdss_dsi_panel_chg_fps_calc(ctrl, dfpks); + } +end: + return rc; +cmd_cnt_err: + pr_err("%s: change fps isn't supported\n", __func__); + return -EINVAL; +disp_onoff_state_err: + pr_err("%s: Disp-On is not yet completed. Please retry\n", __func__); + return -EINVAL; +error: + return -EINVAL; +} + +ssize_t mdss_dsi_panel_driver_change_fpks_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + int dfpks, rc; + + if (!ctrl_pdata || !ctrl_pdata->spec_pdata) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + if (!ctrl_pdata->spec_pdata->chg_fps.enable) { + pr_err("%s: change fps not enabled\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &dfpks); + if (rc < 0) { + pr_err("%s: Error, buf = %s\n", __func__, buf); + return rc; + } + + if (dfpks < 1000 * CHANGE_FPS_MIN + || dfpks > 1000 * CHANGE_FPS_MAX) { + pr_err("%s: invalid value for change_fpks buf = %s\n", + __func__, buf); + return -EINVAL; + } + + if (dfpks == ctrl_pdata->spec_pdata->input_fpks) { + pr_notice("%s: fpks is already %d\n", __func__, dfpks); + return count; + } + + rc = mdss_dsi_panel_chg_fps_check_state(ctrl_pdata, dfpks); + if (rc) { + pr_err("%s: Error, rc = %d\n", __func__, rc); + return rc; + } + return count; +} + +ssize_t mdss_dsi_panel_driver_change_fpks_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct msm_fb_data_type *mfd = mdata->ctl_off->mfd; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + + if (!mdp5_data->ctl || !mdp5_data->ctl->power_state) + return 0; + + return scnprintf(buf, PAGE_SIZE, "%d\n", + ctrl_pdata->spec_pdata->input_fpks); +} + +ssize_t mdss_dsi_panel_driver_change_fps_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + int dfps, dfpks, rc; + + if (!ctrl_pdata || !ctrl_pdata->spec_pdata) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + if (!ctrl_pdata->spec_pdata->chg_fps.enable) { + pr_err("%s: change fps not enabled\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &dfps); + if (rc < 0) { + pr_err("%s: Error, buf = %s\n", __func__, buf); + return rc; + } + + if (dfps >= 1000 * CHANGE_FPS_MIN + && dfps <= 1000 * CHANGE_FPS_MAX) { + dfpks = dfps; + } else if (dfps >= CHANGE_FPS_MIN && dfps <= CHANGE_FPS_MAX) { + dfpks = dfps * 1000; + } else { + pr_err("%s: invalid value for change_fps buf = %s\n", + __func__, buf); + return -EINVAL; + } + + if (dfpks == ctrl_pdata->spec_pdata->input_fpks) { + pr_notice("%s: fpks is already %d\n", __func__, dfpks); + return count; + } + + rc = mdss_dsi_panel_chg_fps_check_state(ctrl_pdata, dfpks); + if (rc) { + pr_err("%s: Error, rc = %d\n", __func__, rc); + return rc; + } + return count; +} + +ssize_t mdss_dsi_panel_driver_change_fps_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = dev_get_drvdata(dev); + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct msm_fb_data_type *mfd = mdata->ctl_off->mfd; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + + if (!mdp5_data->ctl || !mdp5_data->ctl->power_state) + return 0; + + return scnprintf(buf, PAGE_SIZE, "%d\n", + ctrl_pdata->spec_pdata->input_fpks / 1000); +} + +void mdss_dsi_panel_driver_check_splash_enable( + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled) + display_onoff_state = true; + else + display_onoff_state = false; +} + +static void mdss_dsi_panel_driver_chg_fps_cmds_send + (struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct mdss_panel_specific_pdata *spec_pdata = NULL; + u32 fps_cmds, fps_payload; + char rtn; + + spec_pdata = ctrl_pdata->spec_pdata; + + if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE) { + if (spec_pdata->fps_cmds.cmd_cnt) { + fps_cmds = spec_pdata->chg_fps.send_pos.pos[0]; + fps_payload = spec_pdata->chg_fps.send_pos.pos[1]; + rtn = CHANGE_PAYLOAD(fps_cmds, fps_payload); + pr_debug("%s: change fps sequence --- rtn = 0x%x\n", + __func__, rtn); + mdss_dsi_panel_cmds_send(ctrl_pdata, + &ctrl_pdata->spec_pdata->fps_cmds, + CMD_REQ_COMMIT); + } + } +} + +void mdss_dsi_panel_driver_fb_notifier_call_chain( + struct msm_fb_data_type *mfd, int blank, bool type) +{ + struct fb_event event; + + if ((mfd->panel_info->type == MIPI_VIDEO_PANEL) || + (mfd->panel_info->type == MIPI_CMD_PANEL)) { + if (!mdss_dsi_panel_driver_is_incell_operation()) { + event.info = mfd->fbi; + event.data = ␣ + + if (type == FB_NOTIFIER_PRE) + fb_notifier_call_chain( + FB_EXT_EARLY_EVENT_BLANK, &event); + else + fb_notifier_call_chain( + FB_EXT_EVENT_BLANK, &event); + } + } +} + +void mdss_dsi_panel_driver_labibb_vreg_init( + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + int ret; + int min_uV, max_uV = 0; + struct mdss_panel_info *pinfo = NULL; + struct mdss_panel_specific_pdata *spec_pdata = NULL; + struct mdss_panel_labibb_data *labibb = NULL; + struct dss_vreg lab_vreg_config, ibb_vreg_config; + + pinfo = &ctrl_pdata->panel_data.panel_info; + if (!pinfo) { + pr_err("%s: Invalid panel data\n", __func__); + return; + } + + spec_pdata = ctrl_pdata->spec_pdata; + if (!spec_pdata) { + pr_err("%s: Invalid specific panel data\n", __func__); + return; + } + + labibb = &(spec_pdata->labibb); + if (!labibb) { + pr_err("%s: Invalid regulator settings\n", __func__); + return; + } + + + /* + * Get lab/ibb info. + */ + ret = mdss_dsi_panel_driver_vreg_name_to_config(ctrl_pdata, + &lab_vreg_config, "lab"); + if (ret) { + pr_err("%s: lab not registered\n", __func__); + return; + } + + ret = mdss_dsi_panel_driver_vreg_name_to_config(ctrl_pdata, + &ibb_vreg_config, "ibb"); + if (ret) { + pr_err("%s: ibb not registered\n", __func__); + return; + } + + /* + * Set lab/ibb voltage. + */ + + if (((labibb->labibb_ctrl_state) & OVR_LAB_VOLTAGE)) { + min_uV = labibb->lab_output_voltage; + max_uV = min_uV; + ret = regulator_set_voltage(lab_vreg_config.vreg, + min_uV, max_uV); + if (ret) + pr_err("%s: Unable to configure of lab voltage.\n", __func__); + } + + if (((labibb->labibb_ctrl_state) & OVR_IBB_VOLTAGE)) { + min_uV = labibb->ibb_output_voltage; + max_uV = min_uV; + ret = regulator_set_voltage(ibb_vreg_config.vreg, min_uV, max_uV); + if (ret) + pr_err("%s: Unable to configure of ibb voltage.\n", + __func__); + } + + /* + * Set lab/ibb current max + */ + if (((labibb->labibb_ctrl_state) & OVR_LAB_CURRENT_MAX)) { + ret = qpnp_lab_set_current_max(lab_vreg_config.vreg, + labibb->lab_current_max); + if (ret) + pr_err("%s: Unable to configure of lab current_max.\n", + __func__); + } + + if (((labibb->labibb_ctrl_state) & OVR_IBB_CURRENT_MAX)) { + ret = qpnp_ibb_set_current_max(ibb_vreg_config.vreg, + labibb->ibb_current_max); + if (ret) + pr_err("%s: Unable to configure of ibb current_max.\n", + __func__); + } + + /* + * Set lab precharge + */ + if (((labibb->labibb_ctrl_state) & OVR_LAB_PRECHARGE_CTL)) { + ret = qpnp_lab_set_precharge(lab_vreg_config.vreg, + labibb->lab_fast_precharge_time, + labibb->lab_fast_precharge_en); + if (ret) + pr_err("%s: Unable to configure of lab precharge.\n", + __func__); + } + + /* + * Set lab/ibb soft-start control + */ + if (((labibb->labibb_ctrl_state) & OVR_LAB_SOFT_START_CTL)) { + ret = qpnp_lab_set_soft_start(lab_vreg_config.vreg, + labibb->lab_soft_start); + if (ret) + pr_err("%s: Unable to configure of lab soft-start.\n", + __func__); + } + + if (((labibb->labibb_ctrl_state) & OVR_IBB_SOFT_START_CTL)) { + ret = qpnp_ibb_set_soft_start(ibb_vreg_config.vreg, + labibb->ibb_soft_start); + if (ret) + pr_err("%s: Unable to configure of ibb soft-start.\n", + __func__); + } + + /* + * Set lab/ibb pull-down control + */ + if (((labibb->labibb_ctrl_state) & OVR_LAB_PD_CTL)) { + ret = qpnp_lab_set_pull_down(lab_vreg_config.vreg, + labibb->lab_pd_full); + if (ret) + pr_err("%s: Unable to configure of lab pull-down.\n", + __func__); + } + + if (((labibb->labibb_ctrl_state) & OVR_IBB_PD_CTL)) { + ret = qpnp_ibb_set_pull_down(ibb_vreg_config.vreg, + labibb->ibb_pd_full); + if (ret) + pr_err("%s: Unable to configure of ibb pull-down.\n", + __func__); + } +} + +void mdss_dsi_panel_driver_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + ctrl_pdata->spec_pdata->pcc_setup = mdss_dsi_panel_pcc_setup; + ctrl_pdata->spec_pdata->color_mode = CLR_MODE_SELECT_DCIP3; + ctrl_pdata->spec_pdata->esd_enable_without_xlog + = ESD_WITHOUT_XLOG_DISABLE_VALUE; + mdss_dsi_panel_driver_fps_data_init(FPSD); + mdss_dsi_panel_driver_fps_data_init(VPSD); + mdss_dsi_panel_driver_vsync_handler_init(); +} + +void mdss_dsi_panel_driver_off(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + struct mdss_mdp_ctl *ctl = mdata->ctl_off; + + if (ctrl_pdata->spec_pdata->black_screen_off) + ctrl_pdata->spec_pdata->black_screen_off(ctrl_pdata); + + vs_handle.vsync_handler = (mdp_vsync_handler_t)vsync_handler; + vs_handle.cmd_post_flush = false; + vs_handle.enabled = true; + if (vpsd.vps_en && (ctl->ops.remove_vsync_handler)) { + ctl->ops.remove_vsync_handler(ctl, &vs_handle); + vpsd.vps_en = false; + fpsd.fpks = 0; + pr_notice("%s: vsyncs_per_ksecs is invalid\n", __func__); + } + display_onoff_state = false; +} + +void mdss_dsi_panel_driver_post_on(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct mdss_panel_specific_pdata *spec_pdata = NULL; + struct mdss_panel_data *pdata; + + spec_pdata = ctrl_pdata->spec_pdata; + pdata = &(ctrl_pdata->panel_data); + + if (!pdata) + return; + + if (pdata->panel_info.pdest != DISPLAY_1) + return; + + if (spec_pdata->chg_fps.enable) { + if (spec_pdata->chg_fps.mode == FPS_MODE_SUSRES) + mdss_dsi_panel_chg_fps_calc(ctrl_pdata, + spec_pdata->input_fpks); + + mdss_dsi_panel_driver_chg_fps_cmds_send(ctrl_pdata); + } else { + pr_notice("%s: change fps is not supported.\n", __func__); + } + + display_onoff_state = true; +} + +void mdss_dsi_panel_driver_unblank(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + if (ctrl_pdata->spec_pdata->pcc_data.pcc_sts & PCC_STS_UD) { + ctrl_pdata->spec_pdata->pcc_setup(&ctrl_pdata->panel_data); + ctrl_pdata->spec_pdata->pcc_data.pcc_sts &= ~PCC_STS_UD; + } +} + +void mdss_dsi_panel_driver_dump_incell_sts(struct incell_ctrl *incell) +{ + int num; + + pr_err("%s: sts current:0x%x\n", __func__, (int)(incell->state)); + for (num = 0 ; num < INCELL_BACKUP_NUM ; num++) + pr_err("%s: back ups %d :0x%x\n", __func__, + num, (int)(incell->backups[num])); +} + +void mdss_dsi_panel_driver_update_incell_bk(struct incell_ctrl *incell) +{ + int num; + + for (num = INCELL_BACKUP_NUM - 1 ; num > 0 ; num--) + incell->backups[num] = incell->backups[num - 1]; + + incell->backups[0] = incell->state; +} diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel_driver.h b/drivers/video/fbdev/msm/mdss_dsi_panel_driver.h new file mode 100644 index 0000000000000000000000000000000000000000..0bce9d978419869d7288b49360208167e0dc0145 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_dsi_panel_driver.h @@ -0,0 +1,430 @@ +/* drivers/video/fbdev/msm/mdss_dsi_panel_driver.h + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef MDSS_DSI_PANEL_DRIVER_H +#define MDSS_DSI_PANEL_DRIVER_H + +#include + +#include "mdss_dsi.h" +#include "mdss_fb.h" +#include "mdss_mdp.h" + +/* pcc data infomation */ +#define PCC_STS_UD 0x01 /* update request */ +#define UNUSED 0xff +#define CLR_DATA_REG_LEN_RENE_DEFAULT 2 +#define CLR_DATA_REG_LEN_NOVA_DEFAULT 1 +#define CLR_DATA_REG_LEN_NOVA_AUO 3 +#define CLR_DATA_REG_LEN_RENE_SR 1 +enum { + CLR_DATA_UV_PARAM_TYPE_NONE, + CLR_DATA_UV_PARAM_TYPE_RENE_DEFAULT, + CLR_DATA_UV_PARAM_TYPE_NOVA_DEFAULT, + CLR_DATA_UV_PARAM_TYPE_NOVA_AUO, + CLR_DATA_UV_PARAM_TYPE_RENE_SR +}; + +/* color mode */ +#define CLR_MODE_SELECT_SRGB (100) +#define CLR_MODE_SELECT_DCIP3 (101) +#define CLR_MODE_SELECT_PANELNATIVE (102) + +/* fb_notifier call type */ +#define FB_NOTIFIER_PRE ((bool)true) +#define FB_NOTIFIER_POST ((bool)false) + +/* esd */ +#define ESD_WITHOUT_XLOG_ENABLE_VALUE (1) +#define ESD_WITHOUT_XLOG_DISABLE_VALUE (0) + +/* touch I/F data information for incell */ +/* touch I/F or not */ +#define INCELL_TOUCH_RUN ((bool)true) +#define INCELL_TOUCH_IDLE ((bool)false) + +/* incell status */ +#define INCELL_POWER_STATE_ON BIT(0) +#define INCELL_EWU_STATE_ON BIT(1) +#define INCELL_LOCK_STATE_ON BIT(2) +#define INCELL_SYSTEM_STATE_ON BIT(3) + +#define INCELL_POWER_STATE_OFF ~INCELL_POWER_STATE_ON +#define INCELL_EWU_STATE_OFF ~INCELL_EWU_STATE_ON +#define INCELL_LOCK_STATE_OFF ~INCELL_LOCK_STATE_ON +#define INCELL_SYSTEM_STATE_OFF ~INCELL_SYSTEM_STATE_ON + +/* SLE000-P0: Initial setting the case of booting by Kernel */ +#define INCELL_INIT_STATE_KERNEL (0x0f \ + & INCELL_POWER_STATE_OFF \ + & INCELL_EWU_STATE_OFF \ + & INCELL_LOCK_STATE_OFF \ + & INCELL_SYSTEM_STATE_OFF) + +/* SLE100-P1: Initial setting the case of booting by LK */ +#define INCELL_INIT_STATE_LK (INCELL_POWER_STATE_ON \ + | INCELL_SYSTEM_STATE_ON) + +/* The conditions of status if incell_work needed or not */ +#define INCELL_WORK_NEED_P_OFF INCELL_POWER_STATE_ON +#define INCELL_WORK_NEED_P_ON INCELL_SYSTEM_STATE_ON +#define INCELL_WORK_NEED_P_ON_EWU (INCELL_SYSTEM_STATE_ON \ + | INCELL_EWU_STATE_ON) + +#define INCELL_BACKUP_NUM 10 + +/* status to adjust power for incell panel or not */ +typedef enum { + INCELL_WORKER_OFF, + INCELL_WORKER_PENDING, + INCELL_WORKER_ON, +} incell_worker_state; + +/* + * Incell status change mode + * + * SP means the below. + * S : System + * P : Power + */ +typedef enum { + INCELL_STATE_NONE, + INCELL_STATE_S_OFF, + INCELL_STATE_P_OFF, + INCELL_STATE_SP_OFF, + INCELL_STATE_S_ON, + INCELL_STATE_P_ON, + INCELL_STATE_SP_ON, +} incell_state_change; + +/* How to send power sequence */ +typedef enum { + POWER_OFF_EXECUTE, + POWER_OFF_SKIP, + POWER_ON_EXECUTE, + POWER_ON_SKIP, + POWER_ON_EWU_SEQ, +} incell_pw_seq; + +/* control parameters for incell panel */ +struct incell_ctrl { + unsigned char state; + unsigned char backups[INCELL_BACKUP_NUM]; + + incell_state_change change_state; + incell_pw_seq seq; + + bool incell_intf_operation; + incell_intf_mode intf_mode; + + incell_worker_state worker_state; + struct work_struct incell_work; +}; + +#define DEFAULT_FPS_LOG_INTERVAL 100 +#define DEFAULT_FPS_ARRAY_SIZE 120 + +#define HYBRID_INCELL ((bool)true) +#define FULL_INCELL ((bool)false) + +#define CHANGE_FPS_MIN 22 +#define CHANGE_FPS_MAX 60 + +#define CHANGE_FPS_PORCH 2 +#define CHANGE_FPS_SEND 10 + +#define PSEC ((u64)1000000000000) +#define KSEC ((u64)1000) +#define CHANGE_PAYLOAD(a, b) (spec_pdata->fps_cmds.cmds[a].payload[b]) + +typedef enum { + FPS_PORCH_RNG_MIN = 0, + FPS_PORCH_RNG_MAX, + FPS_PORCH_RNG_NUM, +} fps_porch_rng_index; + +typedef enum FPS_TYPE { + FPSD, + VPSD +} fps_type; + +typedef enum FPS_PANEL_TYPE { + FPS_TYPE_UHD_4K, + FPS_TYPE_HYBRID_INCELL, + FPS_TYPE_FULL_INCELL, +} fps_panel_type; + +typedef enum FPS_PANEL_MODE { + FPS_MODE_SUSRES, + FPS_MODE_DYNAMIC, +} fps_panel_mode; + +struct fps_array { + u32 frame_nbr; + u32 time_delta; +}; + +struct fps_data { + struct mutex fps_lock; + u32 log_interval; + u32 interval_ms; + struct timespec timestamp_last; + u32 frame_counter_last; + u32 frame_counter; + u32 fpks; + struct timespec fpks_ts_last; + u16 fa_last_array_pos; + struct fps_array fa[DEFAULT_FPS_ARRAY_SIZE]; + u16 fps_array_cnt; + bool vps_en; +}; + +struct change_fps_send_pos { + int num; + int *pos; +}; + +struct change_fps { + /* common */ + bool enable; + fps_panel_type type; + fps_panel_mode mode; + u32 dric_vdisp; + struct change_fps_send_pos send_pos; + u32 dric_rclk; + u32 dric_total_porch; + u8 chg_fps_type; + u8 chg_fps_mode; + + /* uhd_4k */ + bool rtn_adj; + + /* hybrid */ + u32 dric_mclk; + u32 dric_vtouch; + u32 porch_range[FPS_PORCH_RNG_NUM]; + u16 dric_rtn; + u16 send_byte; + u16 mask_pos; + char mask; + + /* full */ + u32 dric_tp; +}; + +struct mdss_panel_power_seq { + int seq_num; + int *rst_seq; + bool rst_b_seq; + + int disp_vdd; + int disp_vddio; + int disp_vsp; + int disp_vsn; + int disp_dcdc; + int touch_avdd; + int touch_vddio; + int touch_reset; + int touch_reset_first; + int touch_intn; +}; + +struct mdss_pcc_color_tbl { + u32 color_type; + u32 area_num; + u32 u_min; + u32 u_max; + u32 v_min; + u32 v_max; + u32 r_data; + u32 g_data; + u32 b_data; +} __packed; + +struct mdss_pcc_data { + struct mdss_pcc_color_tbl *color_tbl; + u32 tbl_size; + u8 tbl_idx; + u8 pcc_sts; + u32 u_data; + u32 v_data; + int param_type; +}; + +/* lab/ibb control default data */ +#define OVR_LAB_VOLTAGE BIT(0) +#define OVR_IBB_VOLTAGE BIT(1) +#define OVR_LAB_CURRENT_MAX BIT(2) +#define OVR_IBB_CURRENT_MAX BIT(3) +#define OVR_LAB_PRECHARGE_CTL BIT(4) +#define OVR_LAB_SOFT_START_CTL BIT(5) +#define OVR_IBB_SOFT_START_CTL BIT(6) +#define OVR_LAB_PD_CTL BIT(7) +#define OVR_IBB_PD_CTL BIT(8) + +#define QPNP_REGULATOR_VSP_V_5P4V ((u32)5600000) +#define QPNP_REGULATOR_VSN_V_M5P4V ((u32)5600000) +#define LAB_CURRENT_MAX ((u32)200) +#define IBB_CURRENT_MAX ((u32)800) +#define LAB_FAST_PRECHARGE_TIME ((u32)500) +#define LAB_SOFT_START_TIME ((u32)300) +#define IBB_SOFT_START_RESISTOR ((u32)32) + +struct mdss_panel_labibb_data { + u16 labibb_ctrl_state; + + u32 lab_output_voltage; + u32 ibb_output_voltage; + u32 lab_current_max; + u32 ibb_current_max; + u32 lab_fast_precharge_time; + u32 lab_soft_start; + u32 ibb_soft_start; + + bool lab_fast_precharge_en; + bool lab_pd_full; + bool ibb_pd_full; +}; + +struct mdss_panel_specific_pdata { + int disp_vddio_gpio; + int disp_dcdc_en_gpio; + int touch_vddio_gpio; + int touch_reset_gpio; + int touch_int_gpio; + + int color_mode; + bool pcc_enable; + bool srgb_pcc_enable; + bool vivid_pcc_enable; + bool hdr_pcc_enable; + struct dsi_panel_cmds pre_uv_read_cmds; + struct dsi_panel_cmds uv_read_cmds; + struct mdss_pcc_data pcc_data; + struct mdss_pcc_data srgb_pcc_data; + struct mdss_pcc_data vivid_pcc_data; + struct mdss_pcc_data hdr_pcc_data; + + struct mdss_panel_power_seq on_seq; + struct mdss_panel_power_seq off_seq; + u32 down_period; + + struct mdss_panel_labibb_data labibb; + + struct mdss_panel_power_seq ewu_seq; + + int (*pcc_setup)(struct mdss_panel_data *pdata); + + int input_fpks; + struct change_fps chg_fps; + struct dsi_panel_cmds fps_cmds; + + void (*crash_counter_reset)(void); + void (*blackscreen_det)(void); + void (*fff_time_update)(struct mdss_panel_specific_pdata *spec_pdata); + void (*black_screen_off)(struct mdss_dsi_ctrl_pdata *ctrl_pdata); + bool resume_started; + bool panel_type; + + u32 esd_enable_without_xlog; +}; + +void mdss_dsi_panel_driver_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata); +void mdss_dsi_panel_driver_fps_data_update( + struct msm_fb_data_type *mfd, fps_type type); +struct fps_data mdss_dsi_panel_driver_get_fps_data(void); +struct fps_data mdss_dsi_panel_driver_get_vps_data(void); +ssize_t mdss_dsi_panel_driver_vsyncs_per_ksecs_store(struct device *dev, + const char *buf, size_t count); + +ssize_t mdss_dsi_panel_driver_change_fpks_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +ssize_t mdss_dsi_panel_driver_change_fpks_show(struct device *dev, + struct device_attribute *attr, char *buf); +ssize_t mdss_dsi_panel_driver_change_fps_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +ssize_t mdss_dsi_panel_driver_change_fps_show(struct device *dev, + struct device_attribute *attr, char *buf); + +void mdss_dsi_panel_driver_detection(struct platform_device *pdev, + struct device_node **np); +int mdss_dsi_panel_driver_pinctrl_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata); +int mdss_dsi_panel_driver_touch_pinctrl_set_state( + struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool active); +int mdss_dsi_panel_driver_power_off(struct mdss_panel_data *pdata); +int mdss_dsi_panel_driver_power_on(struct mdss_panel_data *pdata); +void mdss_dsi_panel_driver_off(struct mdss_dsi_ctrl_pdata *ctrl_pdata); +void mdss_dsi_panel_driver_post_on(struct mdss_dsi_ctrl_pdata *ctrl_pdata); +int mdss_dsi_panel_driver_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata); +void mdss_dsi_panel_driver_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata); +void mdss_dsi_panel_driver_parse_gpio_params(struct platform_device *ctrl_pdev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata); +int mdss_dsi_panel_driver_reset_panel(struct mdss_panel_data *pdata, + int enable); +int mdss_dsi_panel_driver_reset_touch(struct mdss_panel_data *pdata, + int enable); +int mdss_dsi_panel_driver_reset_dual_display( + struct mdss_dsi_ctrl_pdata *ctrl_pdata); +int mdss_dsi_panel_driver_parse_dt(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl_pdata); +int mdss_dsi_panel_pcc_setup(struct mdss_panel_data *pdata); +void mdss_dsi_panel_driver_fb_notifier_call_chain( + struct msm_fb_data_type *mfd, int blank, bool type); +void mdss_dsi_panel_driver_check_splash_enable( + struct mdss_dsi_ctrl_pdata *ctrl_pdata); +void mdss_dsi_panel_driver_unblank(struct mdss_dsi_ctrl_pdata *ctrl_pdata); +void mdss_dsi_panel_driver_labibb_vreg_init( + struct mdss_dsi_ctrl_pdata *ctrl_pdata); + +/* For incell driver */ +struct incell_ctrl *incell_get_info(void); +void incell_panel_power_worker_canceling(struct incell_ctrl *incell); +void incell_driver_init(void); +bool mdss_dsi_panel_driver_is_power_lock(unsigned char state); +bool mdss_dsi_panel_driver_is_power_on(unsigned char state); +bool mdss_dsi_panel_driver_is_ewu(unsigned char state); +bool mdss_dsi_panel_driver_is_system_on(unsigned char state); +void mdss_dsi_panel_driver_state_change_off(struct incell_ctrl *incell); +void mdss_dsi_panel_driver_power_off_ctrl(struct incell_ctrl *incell); +void mdss_dsi_panel_driver_state_change_on(struct incell_ctrl *incell); +void mdss_dsi_panel_driver_power_on_ctrl(struct incell_ctrl *incell); +struct mdss_panel_specific_pdata *mdss_panel2spec_pdata( + struct mdss_panel_data *pdata); +void mdss_dsi_panel_driver_dump_incell_sts(struct incell_ctrl *incell); +void mdss_dsi_panel_driver_update_incell_bk(struct incell_ctrl *incell); + +/* Qualcomm original function */ +int mdss_dsi_pinctrl_set_state(struct mdss_dsi_ctrl_pdata *ctrl_pdata, + bool active); +int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata); +int mdss_dsi_parse_dcs_cmds(struct device_node *np, + struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key); +void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_panel_cmds *pcmds, u32 flags); + +static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_master_ctrl( + struct mdss_panel_data *pdata) +{ + int dsi_master = DSI_CTRL_0; + + if (pdata->panel_info.dsi_master == DISPLAY_2) + dsi_master = DSI_CTRL_1; + else + dsi_master = DSI_CTRL_0; + + return mdss_dsi_get_ctrl_by_index(dsi_master); +} + +#endif /* MDSS_DSI_PANEL_DRIVER_H */ diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index fe12896332919362ffcc99d3823a936f339d14a5..338dde810adfde6dc8dc4ae0ef0de67645e1b3e7 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -13,6 +13,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -56,6 +61,12 @@ #include "mdss_smmu.h" #include "mdss_mdp.h" +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +#include +#include "mdss_dsi_panel_driver.h" +#include "mdss_dsi_panel_debugfs.h" +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER #define MDSS_FB_NUM 3 #else @@ -82,6 +93,12 @@ */ #define MDP_TIME_PERIOD_CALC_FPS_US 1000000 +#ifdef SOMC_FEATURE_EARLY_UNBLANK +#include +/* with a define we avoid modifying fb.h's FB-enum */ +#define FB_EARLY_UNBLANK 0xC0FFEE +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ + static struct fb_info *fbi_list[MAX_FBI_LIST]; static int fbi_list_index; @@ -271,6 +288,106 @@ static int mdss_fb_notify_update(struct msm_fb_data_type *mfd, return ret; } +#ifdef SOMC_FEATURE_EARLY_UNBLANK +static void mdss_background_unblank(struct work_struct *ws); + +static int pwr_pressed; + +static void +mdss_fb_update_early_unblank_completed(struct msm_fb_data_type *mfd, + bool update) +{ + if (mfd->unblank_kworker) { + pr_debug("early_unblank_complete set to %s\n", + update ? "true" : "false"); + mfd->early_unblank_completed = update; + } +} + +static bool +mdss_fb_did_early_unblank(struct msm_fb_data_type *mfd) +{ + return mfd->early_unblank_completed; +} + +static void +mdss_input_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + /* only react on key down events */ + if (code == KEY_POWER && value == 1) { + pr_debug("power key pressed!"); + pwr_pressed = true; + } +} + +static int +mdss_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "mdss_fb"; + pr_debug("registering %s handle for %s", + handle->name, dev->name); + + error = input_register_handle(handle); + if (error) + goto err2; + + error = input_open_device(handle); + if (error) + goto err1; + + return 0; +err1: + input_unregister_handle(handle); +err2: + kfree(handle); + return error; +} + +static void +mdss_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id mdss_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_KEYBIT, + .keybit = { [BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER) }, + }, + { }, +}; + +static void mdss_ensure_kworker_done(struct workqueue_struct *wq) +{ + if (wq) { + pr_debug("wait for unblank work"); + flush_workqueue(wq); + pr_debug("done waiting for unblank work"); + } +} + +static struct input_handler mdss_input_handler = { + .event = mdss_input_event, + .connect = mdss_input_connect, + .disconnect = mdss_input_disconnect, + .name = "mdss_fb", + .id_table = mdss_ids, +}; +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ + static int lcd_backlight_registered; static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev, @@ -1246,6 +1363,10 @@ static int mdss_fb_probe(struct platform_device *pdev) struct fb_info *fbi; struct mdss_overlay_private *mdp5_data = NULL; int rc; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct incell_ctrl *incell = NULL; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (fbi_list_index >= MAX_FBI_LIST) return -ENOMEM; @@ -1254,6 +1375,11 @@ static int mdss_fb_probe(struct platform_device *pdev) if (!pdata) return -EPROBE_DEFER; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + if (!mdp_instance) { pr_err("mdss mdp resource not initialized yet\n"); return -ENODEV; @@ -1313,6 +1439,12 @@ static int mdss_fb_probe(struct platform_device *pdev) INIT_LIST_HEAD(&mfd->file_list); +#ifdef SOMC_FEATURE_EARLY_UNBLANK + mfd->early_unblank_completed = false; + mfd->unblank_kworker = NULL; + INIT_WORK(&mfd->unblank_work, mdss_background_unblank); +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ + mutex_init(&mfd->bl_lock); mutex_init(&mfd->mdss_sysfs_lock); mutex_init(&mfd->switch_lock); @@ -1395,8 +1527,38 @@ static int mdss_fb_probe(struct platform_device *pdev) if (mdss_fb_register_input_handler(mfd)) pr_err("failed to register input handler\n"); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (mfd->index) + goto skip; + + if ((mfd->panel_info->type == MIPI_VIDEO_PANEL) || + (mfd->panel_info->type == MIPI_CMD_PANEL)) + mdss_dsi_create_debugfs(mfd); + + incell_driver_init(); + incell = incell_get_info(); + if (incell) { + if (mfd->panel_info->cont_splash_enabled) + incell->state = INCELL_INIT_STATE_LK; + pr_debug("%s: state:0x%x touch operation:%d\n", __func__, + (incell->state), (int)(incell->incell_intf_operation)); + + } + +skip: +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work); +#ifdef SOMC_FEATURE_EARLY_UNBLANK + if (mfd->index == 0) { + /* only the primary panel, index 0, uses this kworker */ + mfd->unblank_kworker = + create_singlethread_workqueue("unblanker"); + + } +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ + return rc; } @@ -1489,6 +1651,10 @@ static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd) pr_debug("mdss_fb suspend index=%d\n", mfd->index); +#ifdef SOMC_FEATURE_EARLY_UNBLANK + mdss_ensure_kworker_done(mfd->unblank_kworker); +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ + ret = mdss_fb_pan_idle(mfd); if (ret) { pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d\n", @@ -1512,6 +1678,25 @@ static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd) * as a fall back option, enter ulp state to leave the display * on, but turn off all interface clocks. */ +#ifdef SOMC_FEATURE_EARLY_UNBLANK + /* Check if Early Unblank has done an early power on of + * the panel, but got no request from layers above to do so. + * If that is the case (for instance when a smart cover is + * used), the panel must be manually powered off during + * suspend as no BLANK request will come from above layers. + */ + if (mdss_fb_did_early_unblank(mfd)) { + mdss_fb_update_early_unblank_completed(mfd, false); + + ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi, + mfd->suspend.op_enable); + if (ret) { + pr_err("can't turn off display!\n"); + return ret; + } + mfd->suspend.panel_power_state = mfd->panel_power_state; + } else +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ if (mdss_fb_is_power_on(mfd)) { ret = mdss_fb_blank_sub(BLANK_FLAG_ULP, mfd->fbi, mfd->suspend.op_enable); @@ -1523,6 +1708,11 @@ static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd) mfd->op_enable = false; fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED); } + +#ifdef SOMC_FEATURE_EARLY_UNBLANK + pwr_pressed = false; +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ + exit: return ret; } @@ -1560,8 +1750,17 @@ static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd) * flag. If fb was in ulp state when entering suspend, then nothing * needs to be done. */ +#ifdef SOMC_FEATURE_EARLY_UNBLANK + if (mfd->unblank_kworker && pwr_pressed && + !mdss_panel_is_power_on_ulp(mfd->suspend.panel_power_state)) { + pr_notice("starting unblank async from resume"); + queue_work(mfd->unblank_kworker, &mfd->unblank_work); + } else if (mdss_panel_is_power_on(mfd->suspend.panel_power_state) && + !mdss_panel_is_power_on_ulp(mfd->suspend.panel_power_state)) { +#else if (mdss_panel_is_power_on(mfd->suspend.panel_power_state) && !mdss_panel_is_power_on_ulp(mfd->suspend.panel_power_state)) { +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ int unblank_flag = mdss_panel_is_power_on_interactive( mfd->suspend.panel_power_state) ? FB_BLANK_UNBLANK : BLANK_FLAG_LP; @@ -1870,7 +2069,11 @@ static int mdss_fb_blank_blank(struct msm_fb_data_type *mfd, req_power_state); if (cur_power_state == req_power_state) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + pr_notice("%s: No change in power state\n", __func__); +#else pr_debug("No change in power state\n"); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ return 0; } @@ -1932,7 +2135,11 @@ static int mdss_fb_blank_unblank(struct msm_fb_data_type *mfd) MDSS_PANEL_POWER_ON); if (mdss_panel_is_power_on_interactive(cur_power_state)) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + pr_notice("%s: No change in power state\n", __func__); +#else pr_debug("No change in power state\n"); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ return 0; } @@ -2043,6 +2250,14 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, switch (blank_mode) { case FB_BLANK_UNBLANK: +#ifdef SOMC_FEATURE_EARLY_UNBLANK + mdss_ensure_kworker_done(mfd->unblank_kworker); + mdss_fb_update_early_unblank_completed(mfd, false); + /* if kworker was successful we are done... + * but let's check and retry if not. fall through! + */ + case FB_EARLY_UNBLANK: +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ pr_debug("unblank called. cur pwr state=%d\n", cur_power_state); ret = mdss_fb_blank_unblank(mfd); break; @@ -2076,9 +2291,20 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN: default: +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_fb_notifier_call_chain(mfd, + FB_BLANK_POWERDOWN, FB_NOTIFIER_PRE); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + req_power_state = MDSS_PANEL_POWER_OFF; pr_debug("blank powerdown called\n"); ret = mdss_fb_blank_blank(mfd, req_power_state); + +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (!ret) + mdss_dsi_panel_driver_fb_notifier_call_chain(mfd, + FB_BLANK_POWERDOWN, FB_NOTIFIER_POST); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ break; } @@ -2090,6 +2316,27 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, return ret; } +#ifdef SOMC_FEATURE_EARLY_UNBLANK +static void mdss_background_unblank(struct work_struct *ws) +{ + int ret; + struct msm_fb_data_type *mfd; + mfd = container_of(ws, struct msm_fb_data_type, unblank_work); + + pr_notice("unblank work running"); + + ret = mdss_fb_blank_sub(FB_EARLY_UNBLANK, mfd->fbi, + mfd->op_enable); + + if (ret) { + pr_warn("can't turn on display!\n"); + } else { + mdss_fb_update_early_unblank_completed(mfd, true); + fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING); + } +} +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ + static int mdss_fb_blank(int blank_mode, struct fb_info *info) { int ret; @@ -2888,6 +3135,7 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all) pr_err("PP release failed ret %d\n", ret); } +#ifndef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL /* reset backlight before blank to prevent backlight from * enabling ahead of unblank. for some special cases like * adb shell stop/start. @@ -2895,6 +3143,12 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all) mutex_lock(&mfd->bl_lock); mdss_fb_set_backlight(mfd, 0); mutex_unlock(&mfd->bl_lock); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + +#ifdef SOMC_FEATURE_EARLY_UNBLANK + mdss_ensure_kworker_done(mfd->unblank_kworker); + mdss_fb_update_early_unblank_completed(mfd, false); +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable); @@ -2947,8 +3201,19 @@ static void mdss_fb_power_setting_idle(struct msm_fb_data_type *mfd) static void __mdss_fb_copy_fence(struct msm_sync_pt_data *sync_pt_data, struct sync_fence **fences, u32 *fence_cnt) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct msm_fb_data_type *mfd; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + pr_debug("%s: wait for fences\n", sync_pt_data->fence_name); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mfd = container_of(sync_pt_data, struct msm_fb_data_type, + mdp_sync_pt_data); + if (mfd->spec_mfd.off_sts) + return; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + mutex_lock(&sync_pt_data->sync_mutex); /* * Assuming that acq_fen_cnt is sanitized in bufsync ioctl @@ -3108,11 +3373,22 @@ static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p, struct msm_fb_data_type *mfd; int fence_cnt; int ret = NOTIFY_OK; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct mdss_panel_data *pdata; + struct mdss_panel_specific_pdata *spec_pdata; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ sync_pt_data = container_of(p, struct msm_sync_pt_data, notifier); mfd = container_of(sync_pt_data, struct msm_fb_data_type, mdp_sync_pt_data); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (mfd->spec_mfd.off_sts) { + mdss_fb_signal_timeline(sync_pt_data); + return NOTIFY_OK; + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + switch (event) { case MDP_NOTIFY_FRAME_BEGIN: if (mfd->idle_time && !mod_delayed_work(system_wq, @@ -3143,6 +3419,20 @@ static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p, case MDP_NOTIFY_FRAME_FLUSHED: pr_debug("%s: frame flushed\n", sync_pt_data->fence_name); sync_pt_data->flushed = true; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (mfd->panel.type == MIPI_VIDEO_PANEL || + mfd->panel.type == MIPI_CMD_PANEL) { + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("no panel connected\n"); + return -ENODEV; + } + spec_pdata = mdss_panel2spec_pdata(pdata); + if (spec_pdata->resume_started && spec_pdata->fff_time_update) + spec_pdata->fff_time_update(spec_pdata); + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ break; case MDP_NOTIFY_FRAME_TIMEOUT: pr_err("%s: frame timeout\n", sync_pt_data->fence_name); @@ -3688,6 +3978,10 @@ static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd) int ret = -ENOSYS; u32 new_dsi_mode, dynamic_dsi_switch = 0; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (mfd->spec_mfd.off_sts) + return 0; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (!sync_pt_data->async_wait_fences) mdss_fb_wait_for_fence(sync_pt_data); sync_pt_data->flushed = false; @@ -3720,6 +4014,9 @@ static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd) else pr_warn("no kickoff function setup for fb%d\n", mfd->index); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_fps_data_update(mfd, FPSD); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } else if (fb_backup->atomic_commit) { if (mfd->mdp.kickoff_fnc) ret = mfd->mdp.kickoff_fnc(mfd, @@ -3727,6 +4024,9 @@ static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd) else pr_warn("no kickoff function setup for fb%d\n", mfd->index); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + mdss_dsi_panel_driver_fps_data_update(mfd, FPSD); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ fb_backup->atomic_commit = false; } else { ret = mdss_fb_pan_display_sub(&fb_backup->disp_commit.var, @@ -4934,15 +5234,6 @@ static int __ioctl_wait_idle(struct msm_fb_data_type *mfd, u32 cmd) return ret; } -static bool check_not_supported_ioctl(u32 cmd) -{ - return((cmd == MSMFB_OVERLAY_SET) || (cmd == MSMFB_OVERLAY_UNSET) || - (cmd == MSMFB_OVERLAY_GET) || (cmd == MSMFB_OVERLAY_PREPARE) || - (cmd == MSMFB_DISPLAY_COMMIT) || (cmd == MSMFB_OVERLAY_PLAY) || - (cmd == MSMFB_BUFFER_SYNC) || (cmd == MSMFB_OVERLAY_QUEUE) || - (cmd == MSMFB_NOTIFY_UPDATE)); -} - /* * mdss_fb_do_ioctl() - MDSS Framebuffer ioctl function * @info: pointer to framebuffer info @@ -4970,6 +5261,11 @@ int mdss_fb_do_ioctl(struct fb_info *info, unsigned int cmd, if (!mfd) return -EINVAL; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (mfd->spec_mfd.off_sts) + return 0; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + if (mfd->shutdown_pending) return -ESHUTDOWN; @@ -4977,11 +5273,6 @@ int mdss_fb_do_ioctl(struct fb_info *info, unsigned int cmd, if (!pdata || pdata->panel_info.dynamic_switch_pending) return -EPERM; - if (check_not_supported_ioctl(cmd)) { - pr_err("Unsupported ioctl\n"); - return -EINVAL; - } - atomic_inc(&mfd->ioctl_ref_cnt); mdss_fb_power_setting_idle(mfd); @@ -5196,6 +5487,11 @@ int __init mdss_fb_init(void) if (platform_driver_register(&mdss_fb_driver)) return rc; +#ifdef SOMC_FEATURE_EARLY_UNBLANK + if (input_register_handler(&mdss_input_handler)) + return rc; +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ + return 0; } @@ -5243,11 +5539,21 @@ void mdss_fb_report_panel_dead(struct msm_fb_data_type *mfd) char *envp[2] = {"PANEL_ALIVE=0", NULL}; struct mdss_panel_data *pdata = dev_get_platdata(&mfd->pdev->dev); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + int rc = 0; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (!pdata) { pr_err("Panel data not available\n"); return; } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + rc = qpnp_labibb_ocp_check(); + if (rc) { + pr_notice("%s: ocp check error\n", __func__); + return; + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ pdata->panel_info.panel_dead = true; kobject_uevent_env(&mfd->fbi->dev->kobj, KOBJ_CHANGE, envp); diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 6e52390c2886ea8d2ef303e0e5bc4ec26ea4550c..1e0b4e884d9ffb33892e977afbbae7aa95bfc9ea 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef MDSS_FB_H #define MDSS_FB_H @@ -57,6 +62,13 @@ #define MDP_PP_AD_BL_LINEAR 0x0 #define MDP_PP_AD_BL_LINEAR_INV 0x1 +/* Enables Sonys feature Early Unblank for quick wakeup */ +#define SOMC_FEATURE_EARLY_UNBLANK + +#ifdef SOMC_FEATURE_EARLY_UNBLANK +#include +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ + /** * enum mdp_notify_event - Different frame events to indicate frame update state * @@ -264,6 +276,12 @@ struct msm_fb_fps_info { u32 measured_fps; }; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +struct fb_specific_data { + bool off_sts; +}; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + struct msm_fb_data_type { u32 key; u32 index; @@ -372,6 +390,19 @@ struct msm_fb_data_type { bool pending_switch; struct mutex switch_lock; struct input_handler *input_handler; + +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct fb_specific_data spec_mfd; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ +#ifdef SOMC_FEATURE_EARLY_UNBLANK + /* speed up wakeup */ + /* do unblank (>150ms) on own kworker + * so we don't starve other works + */ + struct workqueue_struct *unblank_kworker; + struct work_struct unblank_work; + bool early_unblank_completed; +#endif /* SOMC_FEATURE_EARLY_UNBLANK */ }; static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd) diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index a49c5290753c0d4f5aef44fe6b4621390df010a9..a953dd1a2ac256dc49c474c391168ef67685ca90 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -62,11 +62,6 @@ #define EDID_VENDOR_ID_SIZE 4 #define EDID_IEEE_REG_ID 0x0c03 -enum edid_sink_mode { - SINK_MODE_DVI, - SINK_MODE_HDMI -}; - enum luminance_value { NO_LUMINANCE_DATA = 3, MAXIMUM_LUMINANCE = 4, @@ -156,13 +151,10 @@ struct hdmi_edid_ctrl { }; static bool hdmi_edid_is_mode_supported(struct hdmi_edid_ctrl *edid_ctrl, - struct msm_hdmi_mode_timing_info *timing, u32 out_format) + struct msm_hdmi_mode_timing_info *timing) { - u32 pclk = hdmi_tx_setup_tmds_clk_rate(timing->pixel_freq, - out_format, false); - if (!timing->supported || - pclk > edid_ctrl->init_data.max_pclk_khz) + timing->pixel_freq > edid_ctrl->init_data.max_pclk_khz) return false; return true; @@ -939,8 +931,7 @@ static void hdmi_edid_add_sink_y420_format(struct hdmi_edid_ctrl *edid_ctrl, u32 ret = hdmi_get_supported_mode(&timing, &edid_ctrl->init_data.ds_data, video_format); - u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, - &timing, MDP_Y_CBCR_H2V2); + u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, &timing); struct hdmi_edid_sink_data *sink = &edid_ctrl->sink_data; if (video_format >= HDMI_VFRMT_MAX) { @@ -1708,8 +1699,7 @@ static void hdmi_edid_add_sink_video_format(struct hdmi_edid_ctrl *edid_ctrl, u32 ret = hdmi_get_supported_mode(&timing, &edid_ctrl->init_data.ds_data, video_format); - u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, - &timing, MDP_RGBA_8888); + u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, &timing); struct hdmi_edid_sink_data *sink_data = &edid_ctrl->sink_data; struct disp_mode_info *disp_mode_list = sink_data->disp_mode_list; u32 i = 0; @@ -2322,13 +2312,6 @@ int hdmi_edid_parser(void *input) goto bail; } - /* Find out if CEA extension blocks exceeding max limit */ - if (num_of_cea_blocks >= MAX_EDID_BLOCKS) { - DEV_WARN("%s: HDMI EDID exceeded max CEA blocks limit\n", - __func__); - num_of_cea_blocks = MAX_EDID_BLOCKS - 1; - } - /* check for valid CEA block */ if (edid_buf[EDID_BLOCK_SIZE] != 2) { DEV_ERR("%s: Invalid CEA block\n", __func__); @@ -2435,7 +2418,7 @@ end: return scaninfo; } /* hdmi_edid_get_sink_scaninfo */ -static u32 hdmi_edid_get_sink_mode(void *input) +u32 hdmi_edid_get_sink_mode(void *input, u32 mode) { struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; bool sink_mode; @@ -2448,8 +2431,13 @@ static u32 hdmi_edid_get_sink_mode(void *input) if (edid_ctrl->edid_override && (edid_ctrl->override_data.sink_mode != -1)) sink_mode = edid_ctrl->override_data.sink_mode; - else - sink_mode = edid_ctrl->sink_mode; + else { + if (edid_ctrl->sink_mode && + (mode > 0 && mode <= HDMI_EVFRMT_END)) + sink_mode = SINK_MODE_HDMI; + else + sink_mode = SINK_MODE_DVI; + } return sink_mode; } /* hdmi_edid_get_sink_mode */ @@ -2464,10 +2452,21 @@ static u32 hdmi_edid_get_sink_mode(void *input) */ bool hdmi_edid_is_dvi_mode(void *input) { - if (hdmi_edid_get_sink_mode(input)) - return false; - else + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + int sink_mode; + + if (!edid_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); return true; + } + + if (edid_ctrl->edid_override && + (edid_ctrl->override_data.sink_mode != -1)) + sink_mode = edid_ctrl->override_data.sink_mode; + else + sink_mode = edid_ctrl->sink_mode; + + return (sink_mode == SINK_MODE_DVI); } /** diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index af802bb45f89f7406fcc7e918ddc7e768e1726ee..c604d0fbf7b2ab43f3c82a4cc2e086cdba9dd903 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -58,10 +58,16 @@ struct hdmi_edid_override_data { int vic; }; +enum edid_sink_mode { + SINK_MODE_DVI, + SINK_MODE_HDMI +}; + int hdmi_edid_parser(void *edid_ctrl); u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size); u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution); bool hdmi_edid_is_dvi_mode(void *input); +u32 hdmi_edid_get_sink_mode(void *edid_ctrl, u32 mode); bool hdmi_edid_sink_scramble_override(void *input); bool hdmi_edid_get_sink_scrambler_support(void *input); bool hdmi_edid_get_scdc_support(void *input); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 1b439eed7dbfc140e06c678002b3954ada09a1a7..b9fd9b156fe252d80d11d37250a81cd0a8b6a53d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -113,7 +118,6 @@ static void hdmi_tx_fps_work(struct work_struct *work); static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, bool active); static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl); -static void hdmi_panel_clear_hdr_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl); static int hdmi_tx_audio_info_setup(struct platform_device *pdev, struct msm_ext_disp_audio_setup_params *params); static int hdmi_tx_get_audio_edid_blk(struct platform_device *pdev, @@ -273,6 +277,20 @@ static void hdmi_tx_cable_notify_work(struct work_struct *work) mutex_unlock(&hdmi_ctrl->tx_lock); } /* hdmi_tx_cable_notify_work */ +static bool hdmi_tx_is_cea_format(int mode) +{ + bool cea_fmt; + + if ((mode > 0) && (mode <= HDMI_EVFRMT_END)) + cea_fmt = true; + else + cea_fmt = false; + + DEV_DBG("%s: %s\n", __func__, cea_fmt ? "Yes" : "No"); + + return cea_fmt; +} + static inline bool hdmi_tx_is_hdcp_enabled(struct hdmi_tx_ctrl *hdmi_ctrl) { return hdmi_ctrl->hdcp_feature_on && @@ -362,11 +380,12 @@ static void hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl) } } -static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl) +static inline bool hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl) { void *data = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); - return hdmi_edid_is_dvi_mode(data); + return (hdmi_edid_get_sink_mode(data, + hdmi_ctrl->vic) == SINK_MODE_DVI); } /* hdmi_tx_is_dvi_mode */ static inline u32 hdmi_tx_is_in_splash(struct hdmi_tx_ctrl *hdmi_ctrl) @@ -411,33 +430,29 @@ static inline void hdmi_tx_cec_device_suspend(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_cec_device_suspend(fd, hdmi_ctrl->panel_suspend); } -static inline void hdmi_tx_send_audio_notification( - struct hdmi_tx_ctrl *hdmi_ctrl, int val) -{ - if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.hpd) { - u32 flags = 0; - - if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) - flags |= MSM_EXT_DISP_HPD_AUDIO; - - if (flags) - hdmi_ctrl->ext_audio_data.intf_ops.hpd( - hdmi_ctrl->ext_pdev, - hdmi_ctrl->ext_audio_data.type, val, flags); - } -} - -static inline void hdmi_tx_send_video_notification( +static inline void hdmi_tx_send_cable_notification( struct hdmi_tx_ctrl *hdmi_ctrl, int val, bool async) { if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.hpd) { u32 flags = 0; - if (async || hdmi_tx_is_in_splash(hdmi_ctrl)) + if (async || hdmi_tx_is_in_splash(hdmi_ctrl)) { flags |= MSM_EXT_DISP_HPD_ASYNC_VIDEO; - else + + if (async) { + if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) + flags |= MSM_EXT_DISP_HPD_ASYNC_AUDIO; + } else + if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) + flags |= MSM_EXT_DISP_HPD_AUDIO; + + } else { flags |= MSM_EXT_DISP_HPD_VIDEO; + if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) + flags |= MSM_EXT_DISP_HPD_AUDIO; + } + hdmi_ctrl->ext_audio_data.intf_ops.hpd(hdmi_ctrl->ext_pdev, hdmi_ctrl->ext_audio_data.type, val, flags); } @@ -450,8 +465,6 @@ static inline void hdmi_tx_ack_state( !hdmi_tx_is_dvi_mode(hdmi_ctrl)) hdmi_ctrl->ext_audio_data.intf_ops.notify(hdmi_ctrl->ext_pdev, val); - - hdmi_tx_send_audio_notification(hdmi_ctrl, val); } static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_panel_data( @@ -843,7 +856,9 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev, mutex_lock(&hdmi_ctrl->tx_lock); - rc = kstrtoint(buf, 10, &hpd); + /* Force HPD to be low */ + /*rc = kstrtoint(buf, 10, &hpd);*/ + rc = kstrtoint("0", 10, &hpd); if (rc) { DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc); goto end; @@ -883,8 +898,7 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev, * No need to blocking wait for display/audio in this * case since HAL is not up so no ACK can be expected. */ - hdmi_tx_send_audio_notification(hdmi_ctrl, 0); - hdmi_tx_send_video_notification(hdmi_ctrl, 0, true); + hdmi_tx_send_cable_notification(hdmi_ctrl, 0, true); } break; @@ -1277,7 +1291,6 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev, { int ret = 0; struct hdmi_tx_ctrl *ctrl = NULL; - u8 hdr_op; ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev); if (!ctrl) { @@ -1298,43 +1311,36 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev, goto end; } - memcpy(&ctrl->hdr_ctrl, buf, sizeof(struct mdp_hdr_stream_ctrl)); + memcpy(&ctrl->hdr_data, buf, sizeof(struct mdp_hdr_stream)); pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", __func__, - ctrl->hdr_ctrl.hdr_stream.eotf, - ctrl->hdr_ctrl.hdr_stream.display_primaries_x[0], - ctrl->hdr_ctrl.hdr_stream.display_primaries_y[0], - ctrl->hdr_ctrl.hdr_stream.display_primaries_x[1], - ctrl->hdr_ctrl.hdr_stream.display_primaries_y[1], - ctrl->hdr_ctrl.hdr_stream.display_primaries_x[2], - ctrl->hdr_ctrl.hdr_stream.display_primaries_y[2]); + ctrl->hdr_data.eotf, + ctrl->hdr_data.display_primaries_x[0], + ctrl->hdr_data.display_primaries_y[0], + ctrl->hdr_data.display_primaries_x[1], + ctrl->hdr_data.display_primaries_y[1], + ctrl->hdr_data.display_primaries_x[2], + ctrl->hdr_data.display_primaries_y[2]); pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", __func__, - ctrl->hdr_ctrl.hdr_stream.white_point_x, - ctrl->hdr_ctrl.hdr_stream.white_point_y, - ctrl->hdr_ctrl.hdr_stream.max_luminance, - ctrl->hdr_ctrl.hdr_stream.min_luminance, - ctrl->hdr_ctrl.hdr_stream.max_content_light_level, - ctrl->hdr_ctrl.hdr_stream.max_average_light_level); + ctrl->hdr_data.white_point_x, + ctrl->hdr_data.white_point_y, + ctrl->hdr_data.max_luminance, + ctrl->hdr_data.min_luminance, + ctrl->hdr_data.max_content_light_level, + ctrl->hdr_data.max_average_light_level); pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", __func__, - ctrl->hdr_ctrl.hdr_stream.pixel_encoding, - ctrl->hdr_ctrl.hdr_stream.colorimetry, - ctrl->hdr_ctrl.hdr_stream.range, - ctrl->hdr_ctrl.hdr_stream.bits_per_component, - ctrl->hdr_ctrl.hdr_stream.content_type); - hdr_op = hdmi_hdr_get_ops(ctrl->curr_hdr_state, - ctrl->hdr_ctrl.hdr_state); + ctrl->hdr_data.pixel_encoding, + ctrl->hdr_data.colorimetry, + ctrl->hdr_data.range, + ctrl->hdr_data.bits_per_component, + ctrl->hdr_data.content_type); - if (hdr_op == HDR_SEND_INFO) - hdmi_panel_set_hdr_infoframe(ctrl); - else if (hdr_op == HDR_CLEAR_INFO) - hdmi_panel_clear_hdr_infoframe(ctrl); - - ctrl->curr_hdr_state = ctrl->hdr_ctrl.hdr_state; + hdmi_panel_set_hdr_infoframe(ctrl); ret = strnlen(buf, PAGE_SIZE); end: @@ -2122,8 +2128,6 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl, goto err; } - /* reset HDR state */ - hdmi_ctrl->curr_hdr_state = HDR_DISABLE; return 0; err: hdmi_tx_deinit_features(hdmi_ctrl, deinit_features); @@ -2384,15 +2388,7 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) mutex_unlock(&hdmi_ctrl->tx_lock); - if (hdmi_ctrl->hpd_state) - hdmi_tx_send_video_notification(hdmi_ctrl, - hdmi_ctrl->hpd_state, true); - else { - hdmi_tx_send_audio_notification(hdmi_ctrl, - hdmi_ctrl->hpd_state); - hdmi_tx_send_video_notification(hdmi_ctrl, - hdmi_ctrl->hpd_state, true); - } + hdmi_tx_send_cable_notification(hdmi_ctrl, hdmi_ctrl->hpd_state, false); } /* hdmi_tx_hpd_int_work */ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl) @@ -2493,7 +2489,8 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) hdmi_ctrl_reg |= BIT(2); /* Set transmission mode to DVI based in EDID info */ - if (hdmi_edid_is_dvi_mode(data)) + if (hdmi_edid_get_sink_mode(data, + hdmi_ctrl->vic) == SINK_MODE_DVI) hdmi_ctrl_reg &= ~BIT(1); /* DVI mode */ /* @@ -2882,12 +2879,11 @@ static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) packet_header = type_code | (version << 8) | (length << 16); DSS_REG_W(io, HDMI_GENERIC0_HDR, packet_header); - packet_payload = (ctrl->hdr_ctrl.hdr_stream.eotf << 8); + packet_payload = (ctrl->hdr_data.eotf << 8); if (hdmi_tx_metadata_type_one(ctrl)) { - packet_payload |= - (descriptor_id << 16) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. - display_primaries_x[0]) << 24); + packet_payload |= (descriptor_id << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[0]) + << 24); DSS_REG_W(io, HDMI_GENERIC0_0, packet_payload); } else { pr_debug("%s: Metadata Type 1 not supported\n", __func__); @@ -2896,56 +2892,44 @@ static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) } packet_payload = - (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.display_primaries_x[0])) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. - display_primaries_y[0]) << 8) - | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. - display_primaries_y[0]) << 16) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. - display_primaries_x[1]) << 24); + (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[0])) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[0]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[0]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[1]) << 24); DSS_REG_W(io, HDMI_GENERIC0_1, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.display_primaries_x[1])) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. - display_primaries_y[1]) << 8) - | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. - display_primaries_y[1]) << 16) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. - display_primaries_x[2]) << 24); + (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[1])) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[1]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[1]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[2]) << 24); DSS_REG_W(io, HDMI_GENERIC0_2, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.display_primaries_x[2])) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. - display_primaries_y[2]) << 8) - | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. - display_primaries_y[2]) << 16) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.white_point_x) << 24); + (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[2])) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[2]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[2]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.white_point_x) << 24); DSS_REG_W(io, HDMI_GENERIC0_3, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.white_point_x)) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.white_point_y) << 8) - | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.white_point_y) << 16) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.max_luminance) << 24); + (HDMI_GET_MSB(ctrl->hdr_data.white_point_x)) + | (HDMI_GET_LSB(ctrl->hdr_data.white_point_y) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.white_point_y) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.max_luminance) << 24); DSS_REG_W(io, HDMI_GENERIC0_4, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.max_luminance)) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.min_luminance) << 8) - | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.min_luminance) << 16) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. - max_content_light_level) << 24); + (HDMI_GET_MSB(ctrl->hdr_data.max_luminance)) + | (HDMI_GET_LSB(ctrl->hdr_data.min_luminance) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.min_luminance) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.max_content_light_level) << 24); DSS_REG_W(io, HDMI_GENERIC0_5, packet_payload); packet_payload = - (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. - max_content_light_level)) - | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. - max_average_light_level) << 8) - | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. - max_average_light_level) << 16); + (HDMI_GET_MSB(ctrl->hdr_data.max_content_light_level)) + | (HDMI_GET_LSB(ctrl->hdr_data.max_average_light_level) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.max_average_light_level) << 16); DSS_REG_W(io, HDMI_GENERIC0_6, packet_payload); enable_packet_control: @@ -2960,38 +2944,11 @@ enable_packet_control: DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control); } -static void hdmi_panel_clear_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) -{ - u32 packet_control = 0; - struct dss_io_data *io = NULL; - - if (!ctrl) { - pr_err("%s: invalid input\n", __func__); - return; - } - - if (!hdmi_tx_is_hdr_supported(ctrl)) { - pr_err("%s: Sink does not support HDR\n", __func__); - return; - } - - io = &ctrl->pdata.io[HDMI_TX_CORE_IO]; - if (!io->base) { - pr_err("%s: core io not inititalized\n", __func__); - return; - } - - packet_control = DSS_REG_R_ND(io, HDMI_GEN_PKT_CTRL); - packet_control &= ~HDMI_GEN_PKT_CTRL_CLR_MASK; - DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control); -} - static int hdmi_tx_audio_info_setup(struct platform_device *pdev, struct msm_ext_disp_audio_setup_params *params) { int rc = 0; struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev); - u32 is_mode_dvi; if (!hdmi_ctrl || !params) { DEV_ERR("%s: invalid input\n", __func__); @@ -3000,9 +2957,8 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev, mutex_lock(&hdmi_ctrl->tx_lock); - is_mode_dvi = hdmi_tx_is_dvi_mode(hdmi_ctrl); - - if (!is_mode_dvi && hdmi_tx_is_panel_on(hdmi_ctrl)) { + if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) && + hdmi_tx_is_panel_on(hdmi_ctrl)) { memcpy(&hdmi_ctrl->audio_params, params, sizeof(struct msm_ext_disp_audio_setup_params)); @@ -3203,10 +3159,6 @@ static int hdmi_tx_power_off(struct hdmi_tx_ctrl *hdmi_ctrl) if (hdmi_ctrl->panel_ops.off) hdmi_ctrl->panel_ops.off(pdata); - hdmi_tx_set_mode(hdmi_ctrl, false); - hdmi_tx_phy_reset(hdmi_ctrl); - hdmi_tx_set_mode(hdmi_ctrl, true); - hdmi_tx_core_off(hdmi_ctrl); hdmi_ctrl->panel_power_on = false; @@ -3231,7 +3183,6 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl) void *pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL); void *edata = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID); - hdmi_ctrl->hdcp_feature_on = hdcp_feature_on; hdmi_ctrl->vic = hdmi_panel_get_vic(&panel_data->panel_info, &hdmi_ctrl->ds_data); @@ -3248,7 +3199,9 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl) } hdmi_ctrl->panel.vic = hdmi_ctrl->vic; - if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) + + if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) && + hdmi_tx_is_cea_format(hdmi_ctrl->vic)) hdmi_ctrl->panel.infoframe = true; else hdmi_ctrl->panel.infoframe = false; @@ -4051,8 +4004,7 @@ static int hdmi_tx_post_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl) &hdmi_ctrl->hpd_int_done, HZ/10); if (!timeout) { pr_debug("cable removed during suspend\n"); - hdmi_tx_send_audio_notification(hdmi_ctrl, 0); - hdmi_tx_send_video_notification(hdmi_ctrl, 0, true); + hdmi_tx_send_cable_notification(hdmi_ctrl, 0, false); } } @@ -4063,8 +4015,7 @@ static int hdmi_tx_post_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl) { if (hdmi_ctrl->panel_suspend) { pr_debug("panel suspend has triggered\n"); - hdmi_tx_send_audio_notification(hdmi_ctrl, 0); - hdmi_tx_send_video_notification(hdmi_ctrl, 0, true); + hdmi_tx_send_cable_notification(hdmi_ctrl, 0, false); } return 0; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h index ad02003631f697f04203126adb015980823929de..3469b8a5819fdf08bbf74afc63a7be353b98d084 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -21,7 +21,6 @@ #include "mdss_hdmi_audio.h" #define MAX_SWITCH_NAME_SIZE 5 -#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x7 enum hdmi_tx_io_type { HDMI_TX_CORE_IO, @@ -91,7 +90,7 @@ struct hdmi_tx_ctrl { struct msm_ext_disp_audio_setup_params audio_params; struct msm_ext_disp_init_data ext_audio_data; struct work_struct fps_work; - struct mdp_hdr_stream_ctrl hdr_ctrl; + struct mdp_hdr_stream hdr_data; spinlock_t hpd_state_lock; @@ -117,7 +116,6 @@ struct hdmi_tx_ctrl { u8 hdcp_status; u8 spd_vendor_name[9]; u8 spd_product_description[17]; - u8 curr_hdr_state; bool hdcp_feature_on; bool hpd_disabled; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index 5bc46d8c8f925b54f22ef030ef13b4c11df544fe..827013d064123aab7c4a6d9e0bbe8dee06e06645 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "mdss_hdmi_util.h" #define RESOLUTION_NAME_STR_LEN 30 @@ -1812,51 +1811,3 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl) return rc; } - -u8 hdmi_hdr_get_ops(u8 curr_state, u8 new_state) -{ - - /** There could be 3 valid state transitions: - * 1. HDR_DISABLE -> HDR_ENABLE - * - * In this transition, we shall start sending - * HDR metadata with metadata from the HDR clip - * - * 2. HDR_ENABLE -> HDR_RESET - * - * In this transition, we will keep sending - * HDR metadata but with EOTF and metadata as 0 - * - * 3. HDR_RESET -> HDR_ENABLE - * - * In this transition, we will start sending - * HDR metadata with metadata from the HDR clip - * - * 4. HDR_RESET -> HDR_DISABLE - * - * In this transition, we will stop sending - * metadata to the sink and clear PKT_CTRL register - * bits. - */ - - if ((curr_state == HDR_DISABLE) - && (new_state == HDR_ENABLE)) { - pr_debug("State changed HDR_DISABLE ---> HDR_ENABLE\n"); - return HDR_SEND_INFO; - } else if ((curr_state == HDR_ENABLE) - && (new_state == HDR_RESET)) { - pr_debug("State changed HDR_ENABLE ---> HDR_RESET\n"); - return HDR_SEND_INFO; - } else if ((curr_state == HDR_RESET) - && (new_state == HDR_ENABLE)) { - pr_debug("State changed HDR_RESET ---> HDR_ENABLE\n"); - return HDR_SEND_INFO; - } else if ((curr_state == HDR_RESET) - && (new_state == HDR_DISABLE)) { - pr_debug("State changed HDR_RESET ---> HDR_DISABLE\n"); - return HDR_CLEAR_INFO; - } - - pr_debug("Unsupported OR no state change\n"); - return HDR_UNSUPPORTED_OP; -} diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h index fe554f8e9e677282e0f500e440dc162335b71a56..4fd659616bcc2590b7154737f00368c1f9ae912f 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2016, 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 @@ -425,12 +425,6 @@ enum hdmi_tx_hdcp2p2_rxstatus_intr_mask { RXSTATUS_REAUTH_REQ = BIT(14), }; -enum hdmi_hdr_op { - HDR_UNSUPPORTED_OP, - HDR_SEND_INFO, - HDR_CLEAR_INFO -}; - struct hdmi_tx_hdcp2p2_ddc_data { enum hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask; u32 timeout_ms; @@ -524,5 +518,5 @@ void hdmi_hdcp2p2_ddc_disable(struct hdmi_tx_ddc_ctrl *ctrl); int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl); int hdmi_utils_get_timeout_in_hysnc(struct msm_hdmi_mode_timing_info *timing, u32 timeout_ms); -u8 hdmi_hdr_get_ops(u8 curr_state, u8 new_state); + #endif /* __HDMI_UTIL_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 410d36a3ac31ece63544acb899bf94190687de45..12bb6d7acec1c755927fe77ff8f9cae80c8a2ad3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -13,6 +13,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -1797,8 +1802,7 @@ static inline int mdss_mdp_irq_clk_register(struct mdss_data_type *mdata, static void __mdss_restore_sec_cfg(struct mdss_data_type *mdata) { - int ret; - u64 scm_ret = 0; + int ret, scm_ret = 0; if (test_bit(MDSS_CAPS_SCM_RESTORE_NOT_REQUIRED, mdata->mdss_caps_map)) return; @@ -1809,7 +1813,7 @@ static void __mdss_restore_sec_cfg(struct mdss_data_type *mdata) ret = scm_restore_sec_cfg(SEC_DEVICE_MDSS, 0, &scm_ret); if (ret || scm_ret) - pr_warn("scm_restore_sec_cfg failed %d %llu\n", + pr_warn("scm_restore_sec_cfg failed %d %d\n", ret, scm_ret); __mdss_mdp_reg_access_clk_enable(mdata, false); @@ -2591,6 +2595,7 @@ static int mdss_mdp_get_cmdline_config(struct platform_device *pdev) len = strlen(mdss_mdp_panel); + len = 0; /* temporary */ if (len > 0) { rc = mdss_mdp_get_pan_cfg(pan_cfg); if (!rc) { @@ -2780,8 +2785,6 @@ ssize_t mdss_mdp_show_capabilities(struct device *dev, SPRINT(" avr"); if (mdss_has_quirk(mdata, MDSS_QUIRK_HDR_SUPPORT_ENABLED)) SPRINT(" hdr"); - if (mdata->nvig_pipes && mdata->mdp_rev >= MDSS_MDP_HW_REV_300) - SPRINT(" vig_csc_db"); /* double buffered VIG CSC block */ SPRINT("\n"); #undef SPRINT @@ -4530,15 +4533,6 @@ static int mdss_mdp_parse_dt_misc(struct platform_device *pdev) mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-clk-factor", &mdata->clk_factor); - /* - * Bus throughput factor will be used during high downscale cases. - * The recommended default factor is 1.1. - */ - mdata->bus_throughput_factor.numer = 11; - mdata->bus_throughput_factor.denom = 10; - mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-bus-througput-factor", - &mdata->bus_throughput_factor); - rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-bandwidth-low-kbps", &mdata->max_bw_low); if (rc) diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index e5a3c80f4530f04b6ccf4db24ef07a7d99785842..feea8986af91796a6ff44120da5a6770c5c5c67a 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -995,8 +995,6 @@ struct mdss_overlay_private { struct task_struct *thread; u8 secure_transition_state; - - bool cache_null_commit; /* Cache if preceding commit was NULL */ }; struct mdss_mdp_set_ot_params { diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 54fb21a5f35d8ef075e5a1e3d715eadb54625a40..efd681a5d9549060d5d9cd7d52c950b9780a6fbb 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -31,7 +31,6 @@ #define MDSS_MDP_QSEED3_VER_DOWNSCALE_LIM 2 #define NUM_MIXERCFG_REGS 3 #define MDSS_MDP_WB_OUTPUT_BPP 3 -#define MIN_BUS_THROUGHPUT_SCALE_FACTOR 35 struct mdss_mdp_mixer_cfg { u32 config_masks[NUM_MIXERCFG_REGS]; bool border_enabled; @@ -623,19 +622,9 @@ static u32 __calc_qseed3_mdp_clk_rate(struct mdss_mdp_pipe *pipe, } static inline bool __is_vert_downscaling(u32 src_h, - struct mdss_rect dst) -{ - return (src_h > dst.h); -} - -static inline bool __is_bus_throughput_factor_required(u32 src_h, - struct mdss_rect dst) -{ - u32 scale_factor = src_h * 10; + struct mdss_rect dst){ - do_div(scale_factor, dst.h); - return (__is_vert_downscaling(src_h, dst) && - (scale_factor >= MIN_BUS_THROUGHPUT_SCALE_FACTOR)); + return (src_h > dst.h); } static u32 get_pipe_mdp_clk_rate(struct mdss_mdp_pipe *pipe, @@ -684,18 +673,10 @@ static u32 get_pipe_mdp_clk_rate(struct mdss_mdp_pipe *pipe, } } - /* - * If the downscale factor is >= 3.5 for a 32 BPP surface, - * it is recommended to add a 10% bus throughput factor to - * the clock rate. - */ - if ((pipe->src_fmt->bpp == 4) && - __is_bus_throughput_factor_required(src_h, dst)) - rate = apply_fudge_factor(rate, &mdata->bus_throughput_factor); - if (flags & PERF_CALC_PIPE_APPLY_CLK_FUDGE) rate = mdss_mdp_clk_fudge_factor(mixer, rate); + rate = min(mdata->max_mdp_clk_rate, rate); return rate; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c index 09d1dab0d180437f9c9d57509f45fa9a9d1e60c8..1035d23fe9ce1493abe8ea625729dda743c101e0 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_debug.c +++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c @@ -1863,14 +1863,12 @@ static void __print_buf(struct seq_file *s, struct mdss_mdp_data *buf, seq_puts(s, "\n"); } -static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe, - struct msm_fb_data_type *mfd) +static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe) { struct mdss_mdp_data *buf; int format; int smps[4]; int i; - struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); seq_printf(s, "\nSSPP #%d type=%s ndx=%x flags=0x%16llx play_cnt=%u xin_id=%d\n", pipe->num, mdss_mdp_pipetype2str(pipe->type), @@ -1925,14 +1923,11 @@ static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe, seq_puts(s, "Data:\n"); - mutex_lock(&mdp5_data->list_lock); list_for_each_entry(buf, &pipe->buf_queue, pipe_list) __print_buf(s, buf, false); - mutex_unlock(&mdp5_data->list_lock); } -static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer, - struct msm_fb_data_type *mfd) +static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer) { struct mdss_mdp_pipe *pipe; int i, cnt = 0; @@ -1949,7 +1944,7 @@ static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer, for (i = 0; i < ARRAY_SIZE(mixer->stage_pipe); i++) { pipe = mixer->stage_pipe[i]; if (pipe) { - __dump_pipe(s, pipe, mfd); + __dump_pipe(s, pipe); cnt++; } } @@ -2024,8 +2019,8 @@ static void __dump_ctl(struct seq_file *s, struct mdss_mdp_ctl *ctl) seq_printf(s, "Play Count=%u Underrun Count=%u\n", ctl->play_cnt, ctl->underrun_cnt); - __dump_mixer(s, ctl->mixer_left, ctl->mfd); - __dump_mixer(s, ctl->mixer_right, ctl->mfd); + __dump_mixer(s, ctl->mixer_left); + __dump_mixer(s, ctl->mixer_right); } static int __dump_mdp(struct seq_file *s, struct mdss_data_type *mdata) diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 747b4e3e2f814228d098a31baa55e43371278b17..e6100ed374e20d8f9fccdd7b4acb5e5a24bce472 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -21,10 +26,16 @@ #include "mdss_debug.h" #include "mdss_mdp_trace.h" #include "mdss_dsi_clk.h" +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +#include "mdss_dsi_panel_driver.h" +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ #include #define MAX_RECOVERY_TRIALS 10 #define MAX_SESSIONS 2 +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +#define MAX_RECOVERY_TRIALS_FOR_ESD 600 +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ #define SPLIT_MIXER_OFFSET 0x800 @@ -1999,6 +2010,11 @@ static int mdss_mdp_cmd_remove_vsync_handler(struct mdss_mdp_ctl *ctl, spin_unlock_irqrestore(&ctx->clk_lock, flags); if (disable_vsync_irq) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (ctx->vsync_irq_cnt == 0) + return 0; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + /* disable rd_ptr interrupt and clocks */ mdss_mdp_setup_vsync(ctx, false); complete(&ctx->stop_comp); @@ -2092,6 +2108,10 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg) struct mdss_panel_data *pdata; unsigned long flags; int rc = 0, te_irq; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct incell_ctrl *incell = incell_get_info(); + struct mdss_panel_specific_pdata *spec_pdata; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx) { @@ -2114,6 +2134,12 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg) if (rc <= 0) { u32 status, mask; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + spec_pdata = mdss_panel2spec_pdata(pdata); + if (spec_pdata->blackscreen_det) + spec_pdata->blackscreen_det(); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + mask = mdss_mdp_get_irq_mask(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP, ctx->current_pp_num); status = mask & readl_relaxed(ctl->mdata->mdp_base + @@ -2160,18 +2186,47 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg) MDSS_XLOG(0xbac); mdss_fb_report_panel_dead(ctl->mfd); } else if (ctx->pp_timeout_report_cnt == 0) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (!incell) + pr_err("%s: Invalid incell data\n", __func__); + else + mdss_dsi_panel_driver_dump_incell_sts(incell); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ MDSS_XLOG(0xbad); MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl", "dsi1_phy", "vbif", "vbif_nrt", - "dbg_bus", "vbif_dbg_bus", - "dsi_dbg_bus", "panic"); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + "dbg_bus", "vbif_dbg_bus", "dsi_dbg_bus"); +#else + "dbg_bus", "vbif_dbg_bus", "dsi_dbg_bus", "panic"); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } else if (ctx->pp_timeout_report_cnt == MAX_RECOVERY_TRIALS) { +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (spec_pdata->esd_enable_without_xlog + == ESD_WITHOUT_XLOG_DISABLE_VALUE) { + MDSS_XLOG(0xbad2); + MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", + "dsi0_phy", + "dsi1_ctrl", "dsi1_phy", "vbif", + "vbif_nrt", + "dbg_bus", "vbif_dbg_bus", "panic"); + mdss_fb_report_panel_dead(ctl->mfd); + } + } else if (ctx->pp_timeout_report_cnt + == MAX_RECOVERY_TRIALS_FOR_ESD) { MDSS_XLOG(0xbad2); MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl", "dsi1_phy", "vbif", "vbif_nrt", "dbg_bus", "vbif_dbg_bus", "dsi_dbg_bus", "panic"); mdss_fb_report_panel_dead(ctl->mfd); +#else + MDSS_XLOG(0xbad2); + MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy", + "dsi1_ctrl", "dsi1_phy", "vbif", "vbif_nrt", + "dbg_bus", "vbif_dbg_bus", "panic"); + mdss_fb_report_panel_dead(ctl->mfd); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } /* disable te irq */ @@ -2332,6 +2387,12 @@ static int mdss_mdp_cmd_panel_on(struct mdss_mdp_ctl *ctl, WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + rc = mdss_mdp_ctl_intf_event(ctl, + MDSS_EVENT_POST_PANEL_ON, NULL, false); + WARN(rc, "intf %d post panel on error (%d)\n", + ctl->intf_num, rc); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } rc = mdss_mdp_tearcheck_enable(ctl, true); @@ -3019,6 +3080,10 @@ static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) struct mdss_mdp_ctl *sctl = NULL, *mctl = ctl; struct mdss_mdp_cmd_ctx *ctx, *sctx = NULL; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct mdss_panel_data *pdata = NULL; + struct mipi_panel_info *mipi = NULL; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx) { @@ -3031,6 +3096,15 @@ static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) return -EPERM; } +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (IS_ERR_OR_NULL(ctl->panel_data)) { + pr_warn("%s: no panel data\n", __func__); + } else { + pdata = ctl->panel_data; + mipi = &pdata->panel_info.mipi; + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + if (!ctl->is_master) { mctl = mdss_mdp_get_main_ctl(ctl); } else { @@ -3091,6 +3165,25 @@ static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) /* * tx dcs command if had any */ +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (ctl->panel_data && mipi && + mipi->dms_mode == DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE && + mipi->switch_mode_pending == true) { + /* enable clks and rd_ptr interrupt */ + mdss_mdp_setup_vsync(ctx, true); + + atomic_inc(&ctx->rdptr_cnt); + MDSS_XLOG(atomic_read(&ctx->rdptr_cnt)); + mdss_mdp_cmd_wait4readptr(ctx); + MDSS_XLOG(atomic_read(&ctx->rdptr_cnt)); + + /* disable clks and rd_ptr interrupt */ + mdss_mdp_setup_vsync(ctx, false); + + mipi->switch_mode_pending = false; + } +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL, CTL_INTF_EVENT_FLAG_DEFAULT); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index bdf6705ef5976c9ca1819e0ef90630aac4a3dcb9..c31c0149866afaa67b4642bd4eafc7c49289e90d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -643,13 +643,8 @@ static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl, display_hctl = (hsync_end_x << 16) | hsync_start_x; den_polarity = 0; - if (ctx->intf_type == MDSS_INTF_HDMI) { - hsync_polarity = p->h_polarity; - vsync_polarity = p->v_polarity; - } else { - hsync_polarity = 0; - vsync_polarity = 0; - } + hsync_polarity = p->h_polarity; + vsync_polarity = p->v_polarity; polarity_ctl = (den_polarity << 2) | /* DEN Polarity */ (vsync_polarity << 1) | /* VSYNC Polarity */ (hsync_polarity << 0); /* HSYNC Polarity */ diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 9e9f37ce0b23ec8bd232c101ced39f2f1e291eba..505dfcc97373abde2174b54b8b118aeaf2ed442c 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -975,31 +975,29 @@ static int __validate_layer_reconfig(struct mdp_input_layer *layer, struct mdss_mdp_pipe *pipe) { int status = 0; - struct mdss_mdp_format_params *layer_src_fmt; + struct mdss_mdp_format_params *src_fmt; struct mdss_data_type *mdata = mfd_to_mdata(pipe->mfd); - bool is_csc_db = (mdata->mdp_rev < MDSS_MDP_HW_REV_300) ? false : true; - - layer_src_fmt = mdss_mdp_get_format_params(layer->buffer.format); - if (!layer_src_fmt) { - pr_err("Invalid layer format %d\n", layer->buffer.format); - status = -EINVAL; - goto err_exit; - } /* - * HW earlier to sdm 3.x.x does not support double buffer CSC. - * Invalidate any reconfig of CSC block on staged pipe. + * csc registers are not double buffered earlier to sdm 3.x.x. + * It is not permitted to change them on staged pipe + * with YUV layer. */ - if (!is_csc_db && - ((!!pipe->src_fmt->is_yuv != !!layer_src_fmt->is_yuv) || - (pipe->src_fmt->is_yuv && layer_src_fmt->is_yuv && - pipe->csc_coeff_set != layer->color_space))) { - pr_err("CSC reconfig not allowed on staged pipe\n"); - status = -EINVAL; - goto err_exit; + if (mdata->mdp_rev < MDSS_MDP_HW_REV_300 && + pipe->csc_coeff_set != layer->color_space) { + src_fmt = mdss_mdp_get_format_params(layer->buffer.format); + if (!src_fmt) { + pr_err("Invalid layer format %d\n", + layer->buffer.format); + status = -EINVAL; + } else { + if (pipe->src_fmt->is_yuv && src_fmt && + src_fmt->is_yuv) { + status = -EPERM; + pr_err("csc change is not permitted on used pipe\n"); + } + } } - -err_exit: return status; } @@ -1853,15 +1851,9 @@ static int __validate_secure_session(struct mdss_overlay_private *mdp5_data) pr_err("secure-camera cnt:%d secure video:%d secure display:%d\n", secure_cam_pipes, secure_vid_pipes, sd_pipes); return -EINVAL; - } else if (mdp5_data->ctl->is_video_mode && - ((sd_pipes && !mdp5_data->sd_enabled) || - (!sd_pipes && mdp5_data->sd_enabled)) && - !mdp5_data->cache_null_commit) { - pr_err("NULL commit missing before display secure session entry/exit\n"); - return -EINVAL; + } else { + return 0; } - - return 0; } /* @@ -3142,14 +3134,6 @@ int mdss_mdp_layer_pre_commit_wfd(struct msm_fb_data_type *mfd, sync_pt_data = &mfd->mdp_sync_pt_data; mutex_lock(&sync_pt_data->sync_mutex); count = sync_pt_data->acq_fen_cnt; - - if (count >= MDP_MAX_FENCE_FD) { - pr_err("Reached maximum possible value for fence count\n"); - mutex_unlock(&sync_pt_data->sync_mutex); - rc = -EINVAL; - goto input_layer_err; - } - sync_pt_data->acq_fen[count] = fence; sync_pt_data->acq_fen_cnt++; mutex_unlock(&sync_pt_data->sync_mutex); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 11c15963074794640895d2f60043e3dfcde59c4f..2638b10c2e1df07523ff8d19bc83d4d7e8933f16 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -2375,8 +2380,6 @@ static void __overlay_set_secure_transition_state(struct msm_fb_data_type *mfd) /* Reset the secure transition state */ mdp5_data->secure_transition_state = SECURE_TRANSITION_NONE; - mdp5_data->cache_null_commit = list_empty(&mdp5_data->pipes_used); - /* * Secure transition would be NONE in two conditions: * 1. All the features are already disabled and state remains @@ -2586,7 +2589,6 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd, ATRACE_BEGIN("sspp_programming"); ret = __overlay_queue_pipes(mfd); ATRACE_END("sspp_programming"); - mutex_unlock(&mdp5_data->list_lock); mdp5_data->kickoff_released = false; @@ -5425,6 +5427,10 @@ static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd, struct msmfb_overlay_data data; struct mdp_set_cfg cfg; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (mfd->spec_mfd.off_sts) + return 0; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ switch (cmd) { case MSMFB_MDP_PP: ret = mdss_mdp_pp_ioctl(mfd, argp); diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index 9c2b1d42bd351499e6041c09bb61f84a8a513885..34610ab6a64a3d6e37a98e2bec399ecd7b6a86a3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -6646,7 +6651,12 @@ static void pp_ad_calc_worker(struct work_struct *work) sysfs_notify_dirent(mdp5_data->ad_event_sd); if (!ad->calc_itr) { ad->state &= ~PP_AD_STATE_VSYNC; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + if (ctl->ops.remove_vsync_handler) + ctl->ops.remove_vsync_handler(ctl, &ad->handle); +#else ctl->ops.remove_vsync_handler(ctl, &ad->handle); +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ } mutex_unlock(&ad->lock); diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c index a5ec7097e0f61ead41e7b570ef10cd751793621f..017a2f10dfbca95e5256b0015e48b356cc615b57 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016, 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 @@ -194,12 +194,8 @@ static int pp_hist_lut_cache_params_pipe_v1_7(struct mdp_hist_lut_data *config, return -EINVAL; } - if (copy_from_user(&hist_lut_usr_config, - (void __user *) config->cfg_payload, - sizeof(hist_lut_usr_config))) { - pr_err("failed to copy hist lut config\n"); - return -EFAULT; - } + memcpy(&hist_lut_usr_config, config->cfg_payload, + sizeof(struct mdp_hist_lut_data_v1_7)); hist_lut_cache_data = pipe->pp_res.hist_lut_cfg_payload; if (!hist_lut_cache_data) { @@ -610,12 +606,8 @@ static int pp_pcc_cache_params_pipe_v1_7(struct mdp_pcc_cfg_data *config, return -EINVAL; } - if (copy_from_user(&v17_usr_config, - (void __user *) config->cfg_payload, - sizeof(v17_usr_config))) { - pr_err("failed to copy pcc config\n"); - return -EFAULT; - } + memcpy(&v17_usr_config, config->cfg_payload, + sizeof(v17_usr_config)); if (!(config->ops & MDP_PP_OPS_WRITE)) { pr_debug("write ops not set value of flag is %d\n", @@ -869,12 +861,8 @@ static int pp_igc_lut_cache_params_pipe_v1_7(struct mdp_igc_lut_data *config, goto igc_config_exit; } - if (copy_from_user(&v17_usr_config, - (void __user *) config->cfg_payload, - sizeof(v17_usr_config))) { - pr_err("failed to copy igc usr config\n"); - return -EFAULT; - } + memcpy(&v17_usr_config, config->cfg_payload, + sizeof(v17_usr_config)); if (!(config->ops & MDP_PP_OPS_WRITE)) { pr_debug("op for gamut %d\n", config->ops); @@ -1284,12 +1272,8 @@ static int pp_pa_cache_params_pipe_v1_7(struct mdp_pa_v2_cfg_data *config, return -EINVAL; } - if (copy_from_user(&pa_usr_config, - (void __user *) config->cfg_payload, - sizeof(pa_usr_config))) { - pr_err("failed to copy pa usr config\n"); - return -EFAULT; - } + memcpy(&pa_usr_config, config->cfg_payload, + sizeof(struct mdp_pa_data_v1_7)); pa_cache_data = pipe->pp_res.pa_cfg_payload; if (!pa_cache_data) { diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c index aabf7c5073765a80e2c6a88cf1a869624bf617b6..d1e3395250888d4a0964240c7c36a2dd73d0cb73 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016, 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 @@ -11,6 +11,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -358,8 +363,7 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, int ret = 0, i = 0; char __iomem *hist_addr; u32 sz = 0, temp = 0, *data = NULL; - struct mdp_hist_lut_data_v1_7 lut_data_v1_7; - struct mdp_hist_lut_data_v1_7 *lut_data = &lut_data_v1_7; + struct mdp_hist_lut_data_v1_7 *lut_data = NULL; struct mdp_hist_lut_data *lut_cfg_data = NULL; if (!base_addr || !cfg_data) { @@ -379,11 +383,7 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, lut_cfg_data->version, lut_cfg_data->cfg_payload); return -EINVAL; } - if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload, - sizeof(*lut_data))) { - pr_err("copy from user failed for lut_data\n"); - return -EFAULT; - } + lut_data = lut_cfg_data->cfg_payload; if (lut_data->len != ENHIST_LUT_ENTRIES) { pr_err("invalid hist_lut len %d", lut_data->len); return -EINVAL; @@ -914,9 +914,10 @@ static int pp_gamut_set_config(char __iomem *base_addr, gamut_val = gamut_data->c1_c2_data[i][j + 1]; gamut_val = (gamut_val << 32) | gamut_data->c0_data[i][j]; - writeq_relaxed(gamut_val, + writeq_relaxed_no_log(gamut_val, base_addr + GAMUT_TABLE_UPPER_R); } + writel_relaxed(gamut_data->c0_data[i][j], base_addr + GAMUT_TABLE_UPPER_R); if ((i >= MDP_GAMUT_SCALE_OFF_TABLE_NUM) || @@ -1767,11 +1768,11 @@ static int pp_igc_set_config(char __iomem *base_addr, data &= ~IGC_INDEX_UPDATE; /* update the index for c0, c1 , c2 */ for (i = 1; i < IGC_LUT_ENTRIES; i++) { - writel_relaxed((lut_data->c0_c1_data[i] & IGC_DATA_MASK) + writel_relaxed_no_log((lut_data->c0_c1_data[i] & IGC_DATA_MASK) | data, c0); - writel_relaxed(((lut_data->c0_c1_data[i] >> 16) + writel_relaxed_no_log(((lut_data->c0_c1_data[i] >> 16) & IGC_DATA_MASK) | data, c1); - writel_relaxed((lut_data->c2_data[i] & IGC_DATA_MASK) + writel_relaxed_no_log((lut_data->c2_data[i] & IGC_DATA_MASK) | data, c2); } bail_out: @@ -1791,8 +1792,7 @@ static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data, { int ret = 0, i = 0; struct mdp_igc_lut_data *lut_cfg_data = NULL; - struct mdp_igc_lut_data_v1_7 lut_data_v1_7; - struct mdp_igc_lut_data_v1_7 *lut_data = &lut_data_v1_7; + struct mdp_igc_lut_data_v1_7 *lut_data = NULL; char __iomem *c1 = NULL, *c2 = NULL; u32 *c0c1_data = NULL, *c2_data = NULL; u32 data = 0, sz = 0; @@ -1816,11 +1816,7 @@ static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data, ret = -EINVAL; goto exit; } - if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload, - sizeof(*lut_data))) { - pr_err("copy from user failed for lut_data\n"); - return -EFAULT; - } + lut_data = lut_cfg_data->cfg_payload; if (lut_data->len != IGC_LUT_ENTRIES) { pr_err("invalid lut len %d\n", lut_data->len); ret = -EINVAL; @@ -1927,15 +1923,15 @@ static int pp_pgc_set_config(char __iomem *base_addr, val = pgc_data_v17->c0_data[i] & PGC_DATA_MASK; val |= (pgc_data_v17->c0_data[i + 1] & PGC_DATA_MASK) << PGC_ODD_SHIFT; - writel_relaxed(val, c0); + writel_relaxed_no_log(val, c0); val = pgc_data_v17->c1_data[i] & PGC_DATA_MASK; val |= (pgc_data_v17->c1_data[i + 1] & PGC_DATA_MASK) << PGC_ODD_SHIFT; - writel_relaxed(val, c1); + writel_relaxed_no_log(val, c1); val = pgc_data_v17->c2_data[i] & PGC_DATA_MASK; val |= (pgc_data_v17->c2_data[i + 1] & PGC_DATA_MASK) << PGC_ODD_SHIFT; - writel_relaxed(val, c2); + writel_relaxed_no_log(val, c2); } if (block_type == DSPP) { val = PGC_SWAP; @@ -1964,24 +1960,20 @@ static int pp_pgc_get_config(char __iomem *base_addr, void *cfg_data, u32 *c0_data = NULL, *c1_data = NULL, *c2_data = NULL; u32 val = 0, i = 0, sz = 0; struct mdp_pgc_lut_data *pgc_data = NULL; - struct mdp_pgc_lut_data_v1_7 pgc_lut_data_v17; - struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = &pgc_lut_data_v17; + struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = NULL; if (!base_addr || !cfg_data) { pr_err("invalid params base_addr %pK cfg_data %pK block_type %d\n", base_addr, cfg_data, block_type); return -EINVAL; } pgc_data = (struct mdp_pgc_lut_data *) cfg_data; - if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data->cfg_payload) { + pgc_data_v17 = (struct mdp_pgc_lut_data_v1_7 *) + pgc_data->cfg_payload; + if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data_v17) { pr_err("invalid pgc version %d payload %pK\n", - pgc_data->version, pgc_data->cfg_payload); + pgc_data->version, pgc_data_v17); return -EINVAL; } - if (copy_from_user(pgc_data_v17, (void __user *) pgc_data->cfg_payload, - sizeof(*pgc_data_v17))) { - pr_err("copy from user failed for pgc lut data\n"); - return -EFAULT; - } if (!(pgc_data->flags & MDP_PP_OPS_READ)) { pr_info("read ops is not set %d", pgc_data->flags); return -EINVAL; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c index b377f09215081a0501cfd98a96cafc68c3f7abe3..25cb94f89dd5545cf2c82e8b5da734ff5c23633d 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016, 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 @@ -298,8 +298,7 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, int ret = 0, i = 0; char __iomem *hist_lut_addr; u32 sz = 0, temp = 0, *data = NULL; - struct mdp_hist_lut_data_v1_7 lut_data_v1_7; - struct mdp_hist_lut_data_v1_7 *lut_data = &lut_data_v1_7; + struct mdp_hist_lut_data_v1_7 *lut_data = NULL; struct mdp_hist_lut_data *lut_cfg_data = NULL; if (!base_addr || !cfg_data) { @@ -324,11 +323,7 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data, lut_cfg_data->version, lut_cfg_data->cfg_payload); return -EINVAL; } - if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload, - sizeof(*lut_data))) { - pr_err("copy from user failed for lut_data\n"); - return -EFAULT; - } + lut_data = lut_cfg_data->cfg_payload; if (lut_data->len != ENHIST_LUT_ENTRIES) { pr_err("invalid hist_lut len %d", lut_data->len); return -EINVAL; diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index e8255ff457265da806ccec3036089d19493cef28..3cfbe665a1e34a599c753178993d0ee1bae5c76c 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef MDSS_PANEL_H #define MDSS_PANEL_H @@ -520,6 +525,9 @@ struct mipi_panel_info { char dma_trigger; /* Dynamic Switch Support */ enum dynamic_mode_switch dms_mode; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + bool switch_mode_pending; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ u32 pixel_packing; u32 dsi_pclk_rate; @@ -928,6 +936,11 @@ struct mdss_panel_info { /* esc clk recommended for the panel */ u32 esc_clk_rate_hz; + +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + const char *panel_id_name; + int dsi_master; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ }; struct mdss_panel_timing { @@ -970,6 +983,10 @@ struct mdss_panel_data { int (*apply_display_setting)(struct mdss_panel_data *pdata, u32 mode); unsigned char *mmss_cc_base; +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL + struct platform_device *panel_pdev; +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + /** * event_handler() - callback handler for MDP core events * @pdata: Pointer refering to the panel struct associated to this diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c index 78bccdbfee3b3f1b06873aa71cb5c8a20b97c8ee..61b0518d3ee636c61c46397097797e31c073d41c 100644 --- a/drivers/video/fbdev/msm/mdss_rotator.c +++ b/drivers/video/fbdev/msm/mdss_rotator.c @@ -373,15 +373,6 @@ static bool mdss_rotator_is_work_pending(struct mdss_rot_mgr *mgr, return false; } -static void mdss_rotator_install_fence_fd(struct mdss_rot_entry_container *req) -{ - int i = 0; - - for (i = 0; i < req->count; i++) - sync_fence_install(req->entries[i].output_fence, - req->entries[i].output_fence_fd); -} - static int mdss_rotator_create_fence(struct mdss_rot_entry *entry) { int ret = 0, fd; @@ -420,6 +411,7 @@ static int mdss_rotator_create_fence(struct mdss_rot_entry *entry) goto get_fd_err; } + sync_fence_install(fence, fd); rot_timeline->next_value++; mutex_unlock(&rot_timeline->lock); @@ -1124,7 +1116,6 @@ static void mdss_rotator_release_from_work_distribution( bool free_perf = false; u32 wb_idx = entry->queue->hw->wb_id; - mutex_lock(&mgr->lock); mutex_lock(&entry->perf->work_dis_lock); if (entry->perf->work_distribution[wb_idx]) entry->perf->work_distribution[wb_idx]--; @@ -1148,7 +1139,6 @@ static void mdss_rotator_release_from_work_distribution( mdss_rotator_clk_ctrl(mgr, false); entry->perf = NULL; } - mutex_unlock(&mgr->lock); } } @@ -2045,6 +2035,7 @@ static int mdss_rotator_close_session(struct mdss_rot_mgr *mgr, list_del_init(&perf->list); mutex_unlock(&perf->work_dis_lock); mutex_unlock(&private->perf_lock); + mutex_unlock(&mgr->lock); if (offload_release_work) goto done; @@ -2057,7 +2048,6 @@ static int mdss_rotator_close_session(struct mdss_rot_mgr *mgr, done: pr_debug("Closed session id:%u", id); ATRACE_END(__func__); - mutex_unlock(&mgr->lock); return 0; } @@ -2250,7 +2240,6 @@ static int mdss_rotator_handle_request(struct mdss_rot_mgr *mgr, goto handle_request_err1; } - mdss_rotator_install_fence_fd(req); mdss_rotator_queue_request(mgr, private, req); mutex_unlock(&mgr->lock); @@ -2411,7 +2400,6 @@ static int mdss_rotator_handle_request32(struct mdss_rot_mgr *mgr, goto handle_request32_err1; } - mdss_rotator_install_fence_fd(req); mdss_rotator_queue_request(mgr, private, req); mutex_unlock(&mgr->lock); diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index bb3b4b3fa9291588d48be68d3009184fe709a130..80dbe83972d73043b9b24f835f6b2f96c28a2fbf 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -2587,8 +2587,7 @@ int mdss_dsi_post_clkon_cb(void *priv, } if (clk & MDSS_DSI_LINK_CLK) { /* toggle the resync FIFO everytime clock changes */ - if ((ctrl->shared_data->phy_rev == DSI_PHY_REV_30) && - !pdata->panel_info.cont_splash_enabled) + if (ctrl->shared_data->phy_rev == DSI_PHY_REV_30) mdss_dsi_phy_v3_toggle_resync_fifo(ctrl); if (ctrl->ulps) { diff --git a/drivers/video/fbdev/ocfb.c b/drivers/video/fbdev/ocfb.c index c9293aea8ec3502e27ddf6125f07201c16996a7b..cbbb018f53d629e3a0d8b25c5cbdd43555a19805 100644 --- a/drivers/video/fbdev/ocfb.c +++ b/drivers/video/fbdev/ocfb.c @@ -7,6 +7,11 @@ * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index e12a797cb82099a7e58c8167ba5a3c9401eb1bab..d655436f408d976619879c096340ad7b372619d3 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c @@ -8,6 +8,11 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c index 11a72bc2c71be64b91480ded3880f0ec97019c42..e0c98423f2c9d0c2203a14933a0061f3026b224e 100644 --- a/drivers/watchdog/bcm_kona_wdt.c +++ b/drivers/watchdog/bcm_kona_wdt.c @@ -304,8 +304,6 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev) if (!wdt) return -ENOMEM; - spin_lock_init(&wdt->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); wdt->base = devm_ioremap_resource(dev, res); if (IS_ERR(wdt->base)) @@ -318,6 +316,7 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev) return ret; } + spin_lock_init(&wdt->lock); platform_set_drvdata(pdev, wdt); watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt); bcm_kona_wdt_wdd.parent = &pdev->dev; diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 8a58bbc14de2de28177577c445cb7d1332b9e90e..7399782c0998eeed033afff74342a73025f831d1 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -409,9 +409,9 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, if (map == SWIOTLB_MAP_ERROR) return DMA_ERROR_CODE; - dev_addr = xen_phys_to_bus(map); xen_dma_map_page(dev, pfn_to_page(map >> PAGE_SHIFT), dev_addr, map & ~PAGE_MASK, size, dir, attrs); + dev_addr = xen_phys_to_bus(map); /* * Ensure that the address returned is DMA'ble @@ -567,14 +567,13 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, sg_dma_len(sgl) = 0; return 0; } - dev_addr = xen_phys_to_bus(map); xen_dma_map_page(hwdev, pfn_to_page(map >> PAGE_SHIFT), dev_addr, map & ~PAGE_MASK, sg->length, dir, attrs); - sg->dma_address = dev_addr; + sg->dma_address = xen_phys_to_bus(map); } else { /* we are not interested in the dma_addr returned by * xen_dma_map_page, only in the potential cache flushes executed diff --git a/fs/Kconfig b/fs/Kconfig index 4adb93ec85eaaba56029de801dd4f9e80aad2a17..a5d2dc39ba07589b58d38522bf79ba46ba0f9eed 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -282,9 +282,4 @@ endif # NETWORK_FILESYSTEMS source "fs/nls/Kconfig" source "fs/dlm/Kconfig" -config FILE_TABLE_DEBUG - bool "Enable FILE_TABLE_DEBUG" - help - This option enables debug of the open files using a global filetable - endmenu diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index 257425511d103cf221946c5cdae41e8938628a0a..ac7d921ed9844b0a0c6afd0e6d4eaf4ca718f955 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c @@ -331,7 +331,7 @@ static int autofs_dev_ioctl_fail(struct file *fp, int status; token = (autofs_wqt_t) param->fail.token; - status = param->fail.status < 0 ? param->fail.status : -ENOENT; + status = param->fail.status ? param->fail.status : -ENOENT; return autofs4_wait_release(sbi, token, status); } diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 8a0243efd35925647aac7b081d3127d07518f60d..0c52941dd62c0d8ccb6d16b41472d9d6ad28fe5f 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -905,60 +905,17 @@ static int load_elf_binary(struct linux_binprm *bprm) elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; vaddr = elf_ppnt->p_vaddr; - /* - * If we are loading ET_EXEC or we have already performed - * the ET_DYN load_addr calculations, proceed normally. - */ if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { elf_flags |= MAP_FIXED; } else if (loc->elf_ex.e_type == ET_DYN) { - /* - * This logic is run once for the first LOAD Program - * Header for ET_DYN binaries to calculate the - * randomization (load_bias) for all the LOAD - * Program Headers, and to calculate the entire - * size of the ELF mapping (total_size). (Note that - * load_addr_set is set to true later once the - * initial mapping is performed.) - * - * There are effectively two types of ET_DYN - * binaries: programs (i.e. PIE: ET_DYN with INTERP) - * and loaders (ET_DYN without INTERP, since they - * _are_ the ELF interpreter). The loaders must - * be loaded away from programs since the program - * may otherwise collide with the loader (especially - * for ET_EXEC which does not have a randomized - * position). For example to handle invocations of - * "./ld.so someprog" to test out a new version of - * the loader, the subsequent program that the - * loader loads must avoid the loader itself, so - * they cannot share the same load range. Sufficient - * room for the brk must be allocated with the - * loader as well, since brk must be available with - * the loader. - * - * Therefore, programs are loaded offset from - * ELF_ET_DYN_BASE and loaders are loaded into the - * independently randomized mmap region (0 load_bias - * without MAP_FIXED). - */ - if (elf_interpreter) { - load_bias = ELF_ET_DYN_BASE; - if (current->flags & PF_RANDOMIZE) - load_bias += arch_mmap_rnd(); - elf_flags |= MAP_FIXED; - } else - load_bias = 0; - - /* - * Since load_bias is used for all subsequent loading - * calculations, we must lower it by the first vaddr - * so that the remaining calculations based on the - * ELF vaddrs will be correctly offset. The result - * is then page aligned. - */ - load_bias = ELF_PAGESTART(load_bias - vaddr); - + /* Try and get dynamic programs out of the way of the + * default mmap base, as well as whatever program they + * might try to exec. This is because the brk will + * follow the loader, and is not movable. */ + load_bias = ELF_ET_DYN_BASE - vaddr; + if (current->flags & PF_RANDOMIZE) + load_bias += arch_mmap_rnd(); + load_bias = ELF_PAGESTART(load_bias); total_size = total_mapping_size(elf_phdata, loc->elf_ex.e_phnum); if (!total_size) { @@ -2338,7 +2295,6 @@ static int elf_core_dump(struct coredump_params *cprm) goto end_coredump; } } - dump_truncate(cprm); if (!elf_core_write_extra_data(cprm)) goto end_coredump; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a61926cb01c0a5f25049afad18c6075157b09d09..863fa0f1972b06653e3438ab3e4fa31723e3ea84 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4397,19 +4397,8 @@ search_again: if (found_type > min_type) { del_item = 1; } else { - if (item_end < new_size) { - /* - * With NO_HOLES mode, for the following mapping - * - * [0-4k][hole][8k-12k] - * - * if truncating isize down to 6k, it ends up - * isize being 8k. - */ - if (btrfs_fs_incompat(root->fs_info, NO_HOLES)) - last_size = new_size; + if (item_end < new_size) break; - } if (found_key.offset >= new_size) del_item = 1; else diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index efd72e1fae74dc168395e5f7b28333048abeda5b..87b87e091e8ed81651b2528e2d7c05d1aa298660 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -849,13 +849,8 @@ cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *fid, __u16 search_flags, struct cifs_search_info *srch_inf) { - int rc; - - rc = CIFSFindFirst(xid, tcon, path, cifs_sb, - &fid->netfid, search_flags, srch_inf, true); - if (rc) - cifs_dbg(FYI, "find first failed=%d\n", rc); - return rc; + return CIFSFindFirst(xid, tcon, path, cifs_sb, + &fid->netfid, search_flags, srch_inf, true); } static int diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 1d125d3d0d898653faba501bba132bca84423b8e..087918c4612a870a3f459cf502a1e0ddf3d9df1b 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -909,7 +909,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); kfree(utf16_path); if (rc) { - cifs_dbg(FYI, "open dir failed rc=%d\n", rc); + cifs_dbg(VFS, "open dir failed\n"); return rc; } @@ -919,7 +919,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, rc = SMB2_query_directory(xid, tcon, fid->persistent_fid, fid->volatile_fid, 0, srch_inf); if (rc) { - cifs_dbg(FYI, "query directory failed rc=%d\n", rc); + cifs_dbg(VFS, "query directory failed\n"); SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); } return rc; diff --git a/fs/coredump.c b/fs/coredump.c index 2ce5ef429c48c22fe8eaaabaa9f1201bf7c19102..fe0a28da18a6992dbf834440d41a8a5c75d29b53 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -810,21 +810,3 @@ int dump_align(struct coredump_params *cprm, int align) return mod ? dump_skip(cprm, align - mod) : 1; } EXPORT_SYMBOL(dump_align); - -/* - * Ensures that file size is big enough to contain the current file - * postion. This prevents gdb from complaining about a truncated file - * if the last "write" to the file was dump_skip. - */ -void dump_truncate(struct coredump_params *cprm) -{ - struct file *file = cprm->file; - loff_t offset; - - if (file->f_op->llseek && file->f_op->llseek != no_llseek) { - offset = file->f_op->llseek(file, 0, SEEK_CUR); - if (i_size_read(file->f_mapping->host) < offset) - do_truncate(file->f_path.dentry, offset, 0, file); - } -} -EXPORT_SYMBOL(dump_truncate); diff --git a/fs/dcache.c b/fs/dcache.c index 4c07a84d13172576f16dd896a510c86e776b0bfe..3a3b0f370304e4230a41209939e85d0e38e8cb39 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1128,12 +1128,11 @@ void shrink_dcache_sb(struct super_block *sb) LIST_HEAD(dispose); freed = list_lru_walk(&sb->s_dentry_lru, - dentry_lru_isolate_shrink, &dispose, 1024); + dentry_lru_isolate_shrink, &dispose, UINT_MAX); this_cpu_sub(nr_dentry_unused, freed); shrink_dentry_list(&dispose); - cond_resched(); - } while (list_lru_count(&sb->s_dentry_lru) > 0); + } while (freed > 0); } EXPORT_SYMBOL(shrink_dcache_sb); diff --git a/fs/ecryptfs/Kconfig b/fs/ecryptfs/Kconfig index 434aa313f077c2789bdef6e1cba0bf2725c37b7b..e31aa9d3fee343b74153a90366a576d8895fe358 100644 --- a/fs/ecryptfs/Kconfig +++ b/fs/ecryptfs/Kconfig @@ -20,3 +20,10 @@ config ECRYPT_FS_MESSAGING Enables the /dev/ecryptfs entry for use by ecryptfsd. This allows for userspace to wrap/unwrap file encryption keys by other backends, like OpenSSL. + +config WTL_ENCRYPTION_FILTER + bool "Enables filtering for some files not to encrypt on eCryptfs" + default y + depends on ECRYPT_FS + help + Modification of encrypted filesystem for SD card encryption diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index cf0186fd9bfe94a7fd9f427d6beabc3d0014afde..cbca0430ee42a6428f8c9cbdda22bc88fd775115 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -22,6 +22,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -145,6 +150,13 @@ static int ecryptfs_crypto_api_algify_cipher_name(char **algified_name, int algified_name_len; int rc; + if (!strncmp(cipher_name, "aes", sizeof("aes")) && + (!strncmp(chaining_modifier, "cbc", sizeof("cbc")) || + !strncmp(chaining_modifier, "xts", sizeof("xts")))) { + cipher_name = "fipsaes"; + cipher_name_len = strnlen(cipher_name, sizeof("fipsaes")); + } + algified_name_len = (chaining_modifier_len + cipher_name_len + 3); (*algified_name) = kmalloc(algified_name_len, GFP_KERNEL); if (!(*algified_name)) { diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index 89e7aa5f178a0793cdbb3fce1b24fe00a9b8c1ad..2b93d1b9aa4bed9e37e40197ef070ce1644aaf7d 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -24,6 +24,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef ECRYPTFS_KERNEL_H #define ECRYPTFS_KERNEL_H @@ -40,6 +45,13 @@ #include #include +#ifdef CONFIG_WTL_ENCRYPTION_FILTER +#define ENC_NAME_FILTER_MAX_INSTANCE 5 +#define ENC_NAME_FILTER_MAX_LEN (256*5) +#define ENC_EXT_FILTER_MAX_INSTANCE 60 +#define ENC_EXT_FILTER_MAX_LEN 16 +#endif + #define ECRYPTFS_DEFAULT_IV_BYTES 16 #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 #define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192 @@ -224,6 +236,9 @@ struct ecryptfs_crypt_stat { #define ECRYPTFS_ENCFN_USE_FEK 0x00001000 #define ECRYPTFS_UNLINK_SIGS 0x00002000 #define ECRYPTFS_I_SIZE_INITIALIZED 0x00004000 +#ifdef CONFIG_WTL_ENCRYPTION_FILTER +#define ECRYPTFS_ENCRYPTED_OTHER_DEVICE 0x00008000 +#endif u32 flags; unsigned int file_version; size_t iv_bytes; @@ -335,6 +350,10 @@ struct ecryptfs_mount_crypt_stat { #define ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK 0x00000020 #define ECRYPTFS_GLOBAL_ENCFN_USE_FEK 0x00000040 #define ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY 0x00000080 +#ifdef CONFIG_WTL_ENCRYPTION_FILTER +#define ECRYPTFS_ENABLE_FILTERING 0x00000100 +#define ECRYPTFS_ENABLE_NEW_PASSTHROUGH 0x00000200 +#endif u32 flags; struct list_head global_auth_tok_list; struct mutex global_auth_tok_list_mutex; @@ -347,6 +366,13 @@ struct ecryptfs_mount_crypt_stat { char global_default_fnek_sig[ECRYPTFS_SIG_SIZE_HEX + 1]; unsigned char global_default_cipher_mode[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1]; +#ifdef CONFIG_WTL_ENCRYPTION_FILTER + int max_name_filter_len; + char enc_filter_name[ENC_NAME_FILTER_MAX_INSTANCE] + [ENC_NAME_FILTER_MAX_LEN + 1]; + char enc_filter_ext[ENC_EXT_FILTER_MAX_INSTANCE] + [ENC_EXT_FILTER_MAX_LEN + 1]; +#endif }; /* superblock private data. */ @@ -771,6 +797,14 @@ int ecryptfs_set_f_namelen(long *namelen, long lower_namelen, int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat, loff_t offset); +#ifdef CONFIG_WTL_ENCRYPTION_FILTER +extern int is_file_name_match(struct ecryptfs_mount_crypt_stat *mcs, + struct dentry *fp_dentry); + +extern int is_file_ext_match(struct ecryptfs_mount_crypt_stat *mcs, + char *str); +#endif + void clean_inode_pages(struct address_space *mapping, pgoff_t start, pgoff_t end); diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index c93fe5fce41ed191954c79ccff310887a62fea82..ca64d8f31dd84bff5330bcee017526b3e4f46b2b 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -22,6 +22,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -33,6 +38,12 @@ #include #include #include "ecryptfs_kernel.h" +#ifdef CONFIG_WTL_ENCRYPTION_FILTER +#include +#define ECRYPTFS_IOCTL_GET_ATTRIBUTES _IOR('l', 0x10, __u32) +#define ECRYPTFS_WAS_ENCRYPTED 0x0080 +#define ECRYPTFS_WAS_ENCRYPTED_OTHER_DEVICE 0x0100 +#endif /** * ecryptfs_read_update_atime @@ -138,6 +149,47 @@ static int read_or_initialize_metadata(struct dentry *dentry) crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mount_crypt_stat = &ecryptfs_superblock_to_private( inode->i_sb)->mount_crypt_stat; + +#ifdef CONFIG_WTL_ENCRYPTION_FILTER + if (crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED + && crypt_stat->flags & ECRYPTFS_POLICY_APPLIED + && crypt_stat->flags & ECRYPTFS_ENCRYPTED + && !(crypt_stat->flags & ECRYPTFS_KEY_VALID) + && !(crypt_stat->flags & ECRYPTFS_KEY_SET) + && crypt_stat->flags & ECRYPTFS_I_SIZE_INITIALIZED) { + crypt_stat->flags |= ECRYPTFS_ENCRYPTED_OTHER_DEVICE; + } + mutex_lock(&crypt_stat->cs_mutex); + if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_NEW_PASSTHROUGH) + && (crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { + if (ecryptfs_read_metadata(dentry)) { + crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED + | ECRYPTFS_ENCRYPTED); + rc = 0; + goto out; + } + } else if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_FILTERING) + && (crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { + struct dentry *fp_dentry = + ecryptfs_inode_to_private(inode)->lower_file->f_path.dentry; + char filename[NAME_MAX+1] = {0}; + if (fp_dentry->d_name.len <= NAME_MAX) + memcpy(filename, fp_dentry->d_name.name, + fp_dentry->d_name.len + 1); + + if (is_file_name_match(mount_crypt_stat, fp_dentry) + || is_file_ext_match(mount_crypt_stat, filename)) { + if (ecryptfs_read_metadata(dentry)) + crypt_stat->flags &= + ~(ECRYPTFS_I_SIZE_INITIALIZED + | ECRYPTFS_ENCRYPTED); + rc = 0; + goto out; + } + } + mutex_unlock(&crypt_stat->cs_mutex); +#endif + mutex_lock(&crypt_stat->cs_mutex); if (crypt_stat->flags & ECRYPTFS_POLICY_APPLIED && @@ -384,6 +436,45 @@ ecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct file *lower_file = ecryptfs_file_to_lower(file); long rc = -ENOTTY; +#ifdef CONFIG_WTL_ENCRYPTION_FILTER + if (cmd == ECRYPTFS_IOCTL_GET_ATTRIBUTES) { + u32 __user *user_attr = (u32 __user *)arg; + u32 attr = 0; + char filename[NAME_MAX+1] = {0}; + struct dentry *ecryptfs_dentry = file->f_path.dentry; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private(ecryptfs_dentry->d_sb) + ->mount_crypt_stat; + + struct inode *inode = d_inode(ecryptfs_dentry); + struct ecryptfs_crypt_stat *crypt_stat = + &ecryptfs_inode_to_private(inode)->crypt_stat; + struct dentry *fp_dentry = + ecryptfs_inode_to_private(inode)->lower_file->f_path.dentry; + if (fp_dentry->d_name.len <= NAME_MAX) + memcpy(filename, fp_dentry->d_name.name, + fp_dentry->d_name.len + 1); + + mutex_lock(&crypt_stat->cs_mutex); + if ((crypt_stat->flags & ECRYPTFS_ENCRYPTED + || crypt_stat->flags & ECRYPTFS_ENCRYPTED_OTHER_DEVICE) + || ((mount_crypt_stat->flags + & ECRYPTFS_ENABLE_FILTERING) + && (is_file_name_match + (mount_crypt_stat, fp_dentry) + || is_file_ext_match + (mount_crypt_stat, filename)))) { + if (crypt_stat->flags & ECRYPTFS_KEY_VALID) + attr = ECRYPTFS_WAS_ENCRYPTED; + else + attr = ECRYPTFS_WAS_ENCRYPTED_OTHER_DEVICE; + } + mutex_unlock(&crypt_stat->cs_mutex); + put_user(attr, user_attr); + return 0; + } +#endif + if (!lower_file->f_op->unlocked_ioctl) return rc; @@ -427,6 +518,87 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #endif +#ifdef CONFIG_WTL_ENCRYPTION_FILTER +int is_file_name_match(struct ecryptfs_mount_crypt_stat *mcs, + struct dentry *fp_dentry) +{ + int i; + char *str = NULL; + if (!(strcmp("/", fp_dentry->d_name.name)) + || !(strcmp("", fp_dentry->d_name.name))) + return 0; + str = kzalloc(mcs->max_name_filter_len + 1, GFP_KERNEL); + if (!str) { + printk(KERN_ERR "%s: Out of memory whilst attempting " + "to kzalloc [%d] bytes\n", __func__, + (mcs->max_name_filter_len + 1)); + return 0; + } + + for (i = 0; i < ENC_NAME_FILTER_MAX_INSTANCE; i++) { + int len = 0; + struct dentry *p = fp_dentry; + if (!strlen(mcs->enc_filter_name[i])) + break; + + while (1) { + if (len == 0) { + len = strlen(p->d_name.name); + if (len > mcs->max_name_filter_len) + break; + strcpy(str, p->d_name.name); + } else { + len = len + 1 + strlen(p->d_name.name) ; + if (len > mcs->max_name_filter_len) + break; + strcat(str, "/"); + strcat(str, p->d_name.name); + } + + if (strncasecmp(str, mcs->enc_filter_name[i], len)) + break; + p = p->d_parent; + + if (!(strcmp("/", p->d_name.name)) + || !(strcmp("", p->d_name.name))) { + if (len == strlen(mcs->enc_filter_name[i])) { + kfree(str); + return 1; + } + break; + } + } + } + kfree(str); + return 0; +} + +int is_file_ext_match(struct ecryptfs_mount_crypt_stat *mcs, char *str) +{ + int i; + char ext[NAME_MAX + 1] = {0}; + + char *token; + int count = 0; + while ((token = strsep(&str, ".")) != NULL) { + strncpy(ext, token, NAME_MAX); + count++; + } + if (count <= 1) + return 0; + + for (i = 0; i < ENC_EXT_FILTER_MAX_INSTANCE; i++) { + if (!strlen(mcs->enc_filter_ext[i])) + return 0; + if (strlen(ext) != strlen(mcs->enc_filter_ext[i])) + continue; + if (!strncasecmp(ext, mcs->enc_filter_ext[i], strlen(ext))) + return 1; + } + return 0; +} +#endif + const struct file_operations ecryptfs_dir_fops = { .iterate = ecryptfs_readdir, .read = generic_read_dir, diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index cb3ecf442d9618dc1357bca11dfbc609c5bc507e..0fd4051cf83bf8ffe51aee7024d9f70e7f4ed0b3 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -22,6 +22,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -243,10 +248,44 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, ecryptfs_dentry, rc); goto out; } +#ifdef CONFIG_WTL_ENCRYPTION_FILTER + mutex_lock(&crypt_stat->cs_mutex); + if (crypt_stat->flags & ECRYPTFS_ENCRYPTED) { + struct dentry *fp_dentry = + ecryptfs_inode_to_private(ecryptfs_inode) + ->lower_file->f_path.dentry; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private(ecryptfs_dentry->d_sb) + ->mount_crypt_stat; + char filename[NAME_MAX+1] = {0}; + if (fp_dentry->d_name.len <= NAME_MAX) + memcpy(filename, fp_dentry->d_name.name, + fp_dentry->d_name.len + 1); + + if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_NEW_PASSTHROUGH) + || ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_FILTERING) && + (is_file_name_match(mount_crypt_stat, fp_dentry) || + is_file_ext_match(mount_crypt_stat, filename)))) { + crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED + | ECRYPTFS_ENCRYPTED); + ecryptfs_put_lower_file(ecryptfs_inode); + } else { + rc = ecryptfs_write_metadata(ecryptfs_dentry, + ecryptfs_inode); + if (rc) + printk( + KERN_ERR "Error writing headers; rc = [%d]\n" + , rc); + ecryptfs_put_lower_file(ecryptfs_inode); + } + } + mutex_unlock(&crypt_stat->cs_mutex); +#else rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); if (rc) printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); ecryptfs_put_lower_file(ecryptfs_inode); +#endif out: return rc; } diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 85f7a289bdac15cd22d467e2b8007f3d38986e50..b7426496ac8017e1e2b5488eb7abf90719dedcec 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -23,6 +23,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -38,6 +43,9 @@ #include #include #include "ecryptfs_kernel.h" +#ifdef CONFIG_WTL_ENCRYPTION_FILTER +#include +#endif /** * Module parameter that defines the ecryptfs_verbosity level. @@ -201,6 +209,9 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes, ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only, ecryptfs_opt_check_dev_ruid, +#ifdef CONFIG_WTL_ENCRYPTION_FILTER + ecryptfs_opt_enable_filtering, +#endif ecryptfs_opt_err }; static const match_table_t tokens = { @@ -218,6 +229,9 @@ static const match_table_t tokens = { {ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"}, {ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"}, {ecryptfs_opt_check_dev_ruid, "ecryptfs_check_dev_ruid"}, +#ifdef CONFIG_WTL_ENCRYPTION_FILTER + {ecryptfs_opt_enable_filtering, "ecryptfs_enable_filtering=%s"}, +#endif {ecryptfs_opt_err, NULL} }; @@ -259,6 +273,56 @@ static void ecryptfs_init_mount_crypt_stat( mount_crypt_stat->flags |= ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED; } +#ifdef CONFIG_WTL_ENCRYPTION_FILTER +static int parse_enc_file_filter_parms( + struct ecryptfs_mount_crypt_stat *mcs, char *str) +{ + char *token = NULL; + int count = 0; + mcs->max_name_filter_len = 0; + while ((token = strsep(&str, "|")) != NULL) { + if (count >= ENC_NAME_FILTER_MAX_INSTANCE) + return -1; + strncpy(mcs->enc_filter_name[count++], + token, ENC_NAME_FILTER_MAX_LEN); + if (mcs->max_name_filter_len < strlen(token)) + mcs->max_name_filter_len = strlen(token); + } + return 0; +} + +static int parse_enc_ext_filter_parms( + struct ecryptfs_mount_crypt_stat *mcs, char *str) +{ + char *token = NULL; + int count = 0; + while ((token = strsep(&str, "|")) != NULL) { + if (count >= ENC_EXT_FILTER_MAX_INSTANCE) + return -1; + strncpy(mcs->enc_filter_ext[count++], + token, ENC_EXT_FILTER_MAX_LEN); + } + return 0; +} + +static int parse_enc_filter_parms( + struct ecryptfs_mount_crypt_stat *mcs, char *str) +{ + char *token = NULL; + if (!strcmp("*", str)) { + mcs->flags |= ECRYPTFS_ENABLE_NEW_PASSTHROUGH; + return 0; + } + token = strsep(&str, ":"); + if (token != NULL) + parse_enc_file_filter_parms(mcs, token); + token = strsep(&str, ":"); + if (token != NULL) + parse_enc_ext_filter_parms(mcs, token); + return 0; +} +#endif + /** * ecryptfs_parse_options * @sb: The ecryptfs super block @@ -418,6 +482,19 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, case ecryptfs_opt_check_dev_ruid: *check_ruid = 1; break; +#ifdef CONFIG_WTL_ENCRYPTION_FILTER + case ecryptfs_opt_enable_filtering: + rc = parse_enc_filter_parms(mount_crypt_stat, + args[0].from); + if (rc) { + printk(KERN_ERR "Error attempting to parse encryption " + "filtering parameters.\n"); + rc = -EINVAL; + goto out; + } + mount_crypt_stat->flags |= ECRYPTFS_ENABLE_FILTERING; + break; +#endif case ecryptfs_opt_err: default: printk(KERN_WARNING diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 25e436ddcf8ef014b495697cd4d87a44627bdf0e..11cbe5340eb31cf9bc2b27263675be0b42d21c6d 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -22,6 +22,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -179,6 +184,10 @@ static int ecryptfs_show_options(struct seq_file *m, struct dentry *root) if (mount_crypt_stat->global_default_cipher_key_size) seq_printf(m, ",ecryptfs_key_bytes=%zd", mount_crypt_stat->global_default_cipher_key_size); +#ifdef CONFIG_WTL_ENCRYPTION_FILTER + if (mount_crypt_stat->flags & ECRYPTFS_ENABLE_FILTERING) + seq_printf(m, ",ecryptfs_enable_filtering"); +#endif if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) seq_printf(m, ",ecryptfs_passthrough"); if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) diff --git a/fs/exec.c b/fs/exec.c index 0428c34d4773225614909ece27cc791e2cc4c328..b1f5ddbf7d5687ca29df3676b94675dc61ba268e 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -206,24 +206,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, if (write) { unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start; - unsigned long ptr_size, limit; - - /* - * Since the stack will hold pointers to the strings, we - * must account for them as well. - * - * The size calculation is the entire vma while each arg page is - * built, so each time we get here it's calculating how far it - * is currently (rather than each call being just the newly - * added size from the arg page). As a result, we need to - * always add the entire size of the pointers, so that on the - * last call to get_arg_page() we'll actually have the entire - * correct size. - */ - ptr_size = (bprm->argc + bprm->envc) * sizeof(void *); - if (ptr_size > ULONG_MAX - size) - goto fail; - size += ptr_size; + struct rlimit *rlim; acct_arg_size(bprm, size / PAGE_SIZE); @@ -235,24 +218,20 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, return page; /* - * Limit to 1/4 of the max stack size or 3/4 of _STK_LIM - * (whichever is smaller) for the argv+env strings. + * Limit to 1/4-th the stack size for the argv+env strings. * This ensures that: * - the remaining binfmt code will not run out of stack space, * - the program will have a reasonable amount of stack left * to work from. */ - limit = _STK_LIM / 4 * 3; - limit = min(limit, rlimit(RLIMIT_STACK) / 4); - if (size > limit) - goto fail; + rlim = current->signal->rlim; + if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) { + put_page(page); + return NULL; + } } return page; - -fail: - put_page(page); - return NULL; } static void put_arg_page(struct page *page) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 61d5bfc7318c88ac0f5d7f7c972b7edeb9c2780c..77d0bc38637ab1f40d65a85be00afafea03c385c 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -19,6 +19,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * Extents support for EXT4 @@ -1304,6 +1309,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, } /* move top-level index/leaf into new block */ + memset(bh->b_data, 0, bh->b_size); memmove(bh->b_data, EXT4_I(inode)->i_data, sizeof(EXT4_I(inode)->i_data)); diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c index c2ee23acf35947f503bd2765de4f88fbb261da7e..5d09ea585840a316257394b193f84e66d8fc5546 100644 --- a/fs/ext4/sysfs.c +++ b/fs/ext4/sysfs.c @@ -100,7 +100,7 @@ static ssize_t reserved_clusters_store(struct ext4_attr *a, int ret; ret = kstrtoull(skip_spaces(buf), 0, &val); - if (ret || val >= clusters) + if (!ret || val >= clusters) return -EINVAL; atomic64_set(&sbi->s_resv_clusters, val); diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig index 182f9ffe2b5162f728a0b38dfc41984039f8eeec..d1c10a1f99c86b5cd894f92014c10d3e7ce2c392 100644 --- a/fs/fat/Kconfig +++ b/fs/fat/Kconfig @@ -74,6 +74,27 @@ config VFAT_FS To compile this as a module, choose M here: the module will be called vfat. +config VFAT_FS_NO_DUALNAMES + bool "disable VFAT dual names support (patent workaround)" + depends on VFAT_FS + help + This option disables support for dual filenames on VFAT filesystems. + If this option is enabled then file creation will either put + a short (8.3) name or a long name on the file, but never both. + The field where a shortname would normally go is filled with + invalid characters such that it cannot be considered a valid + short filename. + + That means that long filenames created with this option + disabled will not be accessible at all to operating systems + that do not understand the FAT long filename extensions. + + Users considering disabling this option should consider the + implications of any patents that may exist on dual filenames + in VFAT. + + If unsure, say N + config FAT_DEFAULT_CODEPAGE int "Default codepage for FAT" depends on MSDOS_FS || VFAT_FS diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 8b2127ffb226cca2ece880d41fd756624c5d3118..492b3eb00ed2b0e761de2152fa4ee44c87db697d 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -498,6 +498,13 @@ parse_record: goto end_of_dir; } + /* + * The FAT_NO_83NAME flag is used to mark files + * created with no 8.3 short name + */ + if (de->lcase & FAT_NO_83NAME) + goto compare_longname; + /* Never prepend '.' to hidden files here. * That is done only for msdos mounts (and only when * 'dotsOK=yes'); if we are executing here, it is in the @@ -511,6 +518,7 @@ parse_record: if (fat_name_match(sbi, name, name_len, bufname, len)) goto found; +compare_longname: if (nr_slots) { void *longname = unicode + FAT_MAX_UNI_CHARS; int size = PATH_MAX - FAT_MAX_UNI_SIZE; @@ -602,6 +610,8 @@ parse_record: if (de->attr != ATTR_EXT && IS_FREE(de->name)) goto record_end; } else { + if (de->lcase & FAT_NO_83NAME) + goto record_end; if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) goto record_end; } @@ -960,6 +970,10 @@ int fat_scan(struct inode *dir, const unsigned char *name, sinfo->bh = NULL; while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh, &sinfo->de) >= 0) { + /* skip files marked as having no 8.3 short name */ + if (sinfo->de->lcase & FAT_NO_83NAME) + continue; + if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) { sinfo->slot_off -= sizeof(*sinfo->de); sinfo->nr_slots = 1; diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 7092584f424af63e66e43cf8ad365343fc18daa9..6dd7912499be21a20139ed1c809928f6876cf880 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -20,6 +20,7 @@ #include #include #include "fat.h" +#include /* * If new entry was created in the parent, it could create the 8.3 @@ -322,6 +323,17 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; int is_shortname; struct shortname_info base_info, ext_info; + unsigned opts_shortname = opts->shortname; + +#ifdef CONFIG_VFAT_FS_NO_DUALNAMES + /* + * When we do not have dualnames, we want to maximise the + * chance that a file will be able to be represented with just + * a 8.3 entry. We can do that by using the WINNT case + * handling extensions to FAT. + */ + opts_shortname = VFAT_SFN_CREATE_WINNT; +#endif is_shortname = 1; INIT_SHORTNAME_INFO(&base_info); @@ -434,9 +446,9 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, if (vfat_find_form(dir, name_res) == 0) return -EEXIST; - if (opts->shortname & VFAT_SFN_CREATE_WIN95) { + if (opts_shortname & VFAT_SFN_CREATE_WIN95) { return (base_info.upper && ext_info.upper); - } else if (opts->shortname & VFAT_SFN_CREATE_WINNT) { + } else if (opts_shortname & VFAT_SFN_CREATE_WINNT) { if ((base_info.upper || base_info.lower) && (ext_info.upper || ext_info.lower)) { if (!base_info.upper && base_info.lower) @@ -575,6 +587,66 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, return 0; } +#ifdef CONFIG_VFAT_FS_NO_DUALNAMES +/* + * This function creates a dummy 8.3 entry which is as compatible as + * possible with existing FAT devices, while not being a valid + * filename under windows or Linux + */ +static void vfat_build_dummy_83_buffer(struct inode *dir, char *msdos_name, + int is_dir) +{ + /* + * These characters are all invalid in 8.3 names, plus have + * been shown to be harmless on all tested devices + */ + const char invalidchar[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0B, + 0x0C, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, + 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x22, 0x2a, + 0x3a, 0x3c, 0x3e, 0x3f, 0x5b, 0x5d, 0x7c }; + int i, tilde_pos, slash_pos; + u32 rand_num = prandom_u32(); + + /* We need a '~' in the prefix to make Win98 happy. */ + tilde_pos = rand_num % 8; + rand_num >>= 3; + + /* + * the '/' makes sure that even unpatched Linux systems can't + * get at files by the 8.3 entry. Don't put in a / in + * directories as it can cause problems with some + * photo frames + */ + if (is_dir) + slash_pos = -1; + else { + slash_pos = (tilde_pos + 1 + rand_num % 7) % 8; + rand_num >>= 3; + } + + /* + * fill in the first 8 bytes with invalid characters. Note + * that we need to be careful not to run out of randomness. We + * leave the 3 byte extension in place as some cheap MP3 + * players need them. + */ + for (i = 0; i < 8; i++) { + if (i == tilde_pos) + msdos_name[i] = '~'; + else if (i == slash_pos) + msdos_name[i] = '/'; + else { + msdos_name[i] = + invalidchar[rand_num % sizeof(invalidchar)]; + rand_num /= sizeof(invalidchar); + if (rand_num < sizeof(invalidchar)) + rand_num = prandom_u32(); + } + } +} +#endif + static int vfat_build_slots(struct inode *dir, const unsigned char *name, int len, int is_dir, int cluster, struct timespec *ts, @@ -617,6 +689,13 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name, goto shortname; } +#ifdef CONFIG_VFAT_FS_NO_DUALNAMES + printk_once(KERN_INFO + "VFAT: not creating 8.3 short filenames for long names\n"); + vfat_build_dummy_83_buffer(dir, msdos_name, is_dir); + lcase = FAT_NO_83NAME; +#endif + /* build the entry of long file name */ cksum = fat_checksum(msdos_name); diff --git a/fs/fcntl.c b/fs/fcntl.c index 62376451bbcedef811f4e5db6398b7959058698f..ee85cd4e136abbff33409fb018343028d21578e2 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -740,10 +740,16 @@ static int __init fcntl_init(void) * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY * is defined as O_NONBLOCK on some platforms and not on others. */ - BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != - HWEIGHT32( - (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | - __FMODE_EXEC | __FMODE_NONOTIFY)); + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( + O_RDONLY | O_WRONLY | O_RDWR | + O_CREAT | O_EXCL | O_NOCTTY | + O_TRUNC | O_APPEND | /* O_NONBLOCK | */ + __O_SYNC | O_DSYNC | FASYNC | + O_DIRECT | O_LARGEFILE | O_DIRECTORY | + O_NOFOLLOW | O_NOATIME | O_CLOEXEC | + __FMODE_EXEC | O_PATH | __O_TMPFILE | + __FMODE_NONOTIFY + )); fasync_cache = kmem_cache_create("fasync_cache", sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL); diff --git a/fs/file_table.c b/fs/file_table.c index b4baa0de49885f1a81612f549c44864cee28c676..ad17e05ebf95f07888b15f2b09a7b37ac89b9710 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -41,141 +41,6 @@ static struct kmem_cache *filp_cachep __read_mostly; static struct percpu_counter nr_files __cacheline_aligned_in_smp; -#ifdef CONFIG_FILE_TABLE_DEBUG -#include -#include -static DEFINE_MUTEX(global_files_lock); -static DEFINE_HASHTABLE(global_files_hashtable, 10); - -struct global_filetable_lookup_key { - struct work_struct work; - uintptr_t value; -}; - -void global_filetable_print_warning_once(void) -{ - pr_err_once("\n**********************************************************\n"); - pr_err_once("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); - pr_err_once("** **\n"); - pr_err_once("** VFS FILE TABLE DEBUG is enabled . **\n"); - pr_err_once("** Allocating extra memory and slowing access to files **\n"); - pr_err_once("** **\n"); - pr_err_once("** This means that this is a DEBUG kernel and it is **\n"); - pr_err_once("** unsafe for production use. **\n"); - pr_err_once("** **\n"); - pr_err_once("** If you see this message and you are not debugging **\n"); - pr_err_once("** the kernel, report this immediately to your vendor! **\n"); - pr_err_once("** **\n"); - pr_err_once("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); - pr_err_once("**********************************************************\n"); -} - -void global_filetable_add(struct file *filp) -{ - struct mount *mnt; - - if (filp->f_path.dentry->d_iname == NULL || - strlen(filp->f_path.dentry->d_iname) == 0) - return; - - mnt = real_mount(filp->f_path.mnt); - - mutex_lock(&global_files_lock); - hash_add(global_files_hashtable, &filp->f_hash, (uintptr_t)mnt); - mutex_unlock(&global_files_lock); -} - -void global_filetable_del(struct file *filp) -{ - mutex_lock(&global_files_lock); - hash_del(&filp->f_hash); - mutex_unlock(&global_files_lock); -} - -static void global_print_file(struct file *filp, char *path_buffer, int *count) -{ - char *pathname; - - pathname = d_path(&filp->f_path, path_buffer, PAGE_SIZE); - if (IS_ERR(pathname)) - pr_err("VFS: File %d Address : %pa partial filename: %s ref_count=%ld\n", - ++(*count), &filp, filp->f_path.dentry->d_iname, - atomic_long_read(&filp->f_count)); - else - pr_err("VFS: File %d Address : %pa full filepath: %s ref_count=%ld\n", - ++(*count), &filp, pathname, - atomic_long_read(&filp->f_count)); -} - -static void global_filetable_print(uintptr_t lookup_mnt) -{ - struct hlist_node *tmp; - struct file *filp; - struct mount *mnt; - int index; - int count = 0; - char *path_buffer = (char *)__get_free_page(GFP_TEMPORARY); - - mutex_lock(&global_files_lock); - pr_err("\n**********************************************************\n"); - pr_err("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); - - pr_err("\n"); - pr_err("VFS: The following files hold a reference to the mount\n"); - pr_err("\n"); - hash_for_each_possible_safe(global_files_hashtable, filp, tmp, f_hash, - lookup_mnt) { - mnt = real_mount(filp->f_path.mnt); - if ((uintptr_t)mnt == lookup_mnt) - global_print_file(filp, path_buffer, &count); - } - pr_err("\n"); - pr_err("VFS: Found total of %d open files\n", count); - pr_err("\n"); - - count = 0; - pr_err("\n"); - pr_err("VFS: The following files need to cleaned up\n"); - pr_err("\n"); - hash_for_each_safe(global_files_hashtable, index, tmp, filp, f_hash) { - if (atomic_long_read(&filp->f_count) == 0) - global_print_file(filp, path_buffer, &count); - } - - pr_err("\n"); - pr_err("VFS: Found total of %d files awaiting clean-up\n", count); - pr_err("\n"); - pr_err("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); - pr_err("\n**********************************************************\n"); - - mutex_unlock(&global_files_lock); - free_page((unsigned long)path_buffer); -} - -static void global_filetable_print_work_fn(struct work_struct *work) -{ - struct global_filetable_lookup_key *key; - uintptr_t lookup_mnt; - - key = container_of(work, struct global_filetable_lookup_key, work); - lookup_mnt = key->value; - kfree(key); - global_filetable_print(lookup_mnt); -} - -void global_filetable_delayed_print(struct mount *mnt) -{ - struct global_filetable_lookup_key *key; - - key = kzalloc(sizeof(*key), GFP_KERNEL); - if (key == NULL) - return; - key->value = (uintptr_t)mnt; - INIT_WORK(&key->work, global_filetable_print_work_fn); - schedule_work(&key->work); -} -#endif /* CONFIG_FILE_TABLE_DEBUG */ - static void file_free_rcu(struct rcu_head *head) { struct file *f = container_of(head, struct file, f_u.fu_rcuhead); @@ -354,7 +219,6 @@ static void __fput(struct file *file) put_write_access(inode); __mnt_drop_write(mnt); } - global_filetable_del(file); file->f_path.dentry = NULL; file->f_path.mnt = NULL; file->f_inode = NULL; @@ -450,7 +314,6 @@ void __init files_init(void) filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); percpu_counter_init(&nr_files, 0, GFP_KERNEL); - global_filetable_print_warning_once(); } /* diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index b237862dc2740f36219562feebdfc01fe45e5419..72ae68f0f7a6d4b649720b44bb1725f520e517a6 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -5,6 +5,11 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "fuse_i.h" @@ -1626,6 +1631,12 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff) return fuse_simple_request(fc, &args); } +static bool fuse_allow_set_time(struct fuse_conn *fc, struct inode *inode) +{ + return (fc->flags & FUSE_ALLOW_UTIME_GRP && inode->i_mode & S_IWGRP && + !uid_eq(current_uid(), inode->i_uid) && in_group_p(inode->i_gid)); +} + /* * Set attributes, and at the same time refresh them. * @@ -1645,13 +1656,22 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, bool is_truncate = false; bool is_wb = fc->writeback_cache; loff_t oldsize; + unsigned int ia_valid; int err; bool trust_local_cmtime = is_wb && S_ISREG(inode->i_mode); if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) attr->ia_valid |= ATTR_FORCE; + ia_valid = attr->ia_valid; + if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) && + fuse_allow_set_time(fc, inode)) { + attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET | + ATTR_TIMES_SET); + } + err = inode_change_ok(inode, attr); + attr->ia_valid = ia_valid; if (err) return err; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 1cc0dce47a2fc59cc77859615c66b8bcb6e4f1ca..316acdbdf2a7f6a3daa3fdb35b82127719444e08 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -5,6 +5,11 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _FS_FUSE_I_H #define _FS_FUSE_I_H @@ -45,6 +50,11 @@ doing the mount will be allowed to access the filesystem */ #define FUSE_ALLOW_OTHER (1 << 1) +/** If the FUSE_ALLOW_UTIME_GRP flag is given, then call to utime() is + allowed for the current process if it's in the same group as the + file and if the file's group is writeable */ +#define FUSE_ALLOW_UTIME_GRP (1 << 2) + /** Number of page pointers embedded in fuse_req */ #define FUSE_REQ_INLINE_PAGES 1 diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 43bb5eb17ad2e1b9dd66a5021d60675be2947ea4..c06644a7fefebbafb77500e59eb18482f7927dc4 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -5,6 +5,11 @@ This program can be distributed under the terms of the GNU GPL. See the file COPYING. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "fuse_i.h" @@ -438,6 +443,7 @@ enum { OPT_GROUP_ID, OPT_DEFAULT_PERMISSIONS, OPT_ALLOW_OTHER, + OPT_ALLOW_UTIME_GRP, OPT_MAX_READ, OPT_BLKSIZE, OPT_ERR @@ -450,6 +456,7 @@ static const match_table_t tokens = { {OPT_GROUP_ID, "group_id=%u"}, {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, {OPT_ALLOW_OTHER, "allow_other"}, + {OPT_ALLOW_UTIME_GRP, "allow_utime_grp"}, {OPT_MAX_READ, "max_read=%u"}, {OPT_BLKSIZE, "blksize=%u"}, {OPT_ERR, NULL} @@ -525,6 +532,10 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) d->flags |= FUSE_ALLOW_OTHER; break; + case OPT_ALLOW_UTIME_GRP: + d->flags |= FUSE_ALLOW_UTIME_GRP; + break; + case OPT_MAX_READ: if (match_int(&args[0], &value)) return 0; @@ -560,6 +571,8 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root) seq_puts(m, ",default_permissions"); if (fc->flags & FUSE_ALLOW_OTHER) seq_puts(m, ",allow_other"); + if (fc->flags & FUSE_ALLOW_UTIME_GRP) + seq_puts(m, ",allow_utime_grp"); if (fc->max_read != ~0) seq_printf(m, ",max_read=%u", fc->max_read); if (sb->s_bdev && sb->s_blocksize != FUSE_DEFAULT_BLKSIZE) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 070901e76653a306a2c961c5a5b8bafcd40157ca..9cd8c92b953d164294fcc48a5bc5e4a415732fd4 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -80,9 +80,9 @@ static struct rhashtable_params ht_parms = { static struct rhashtable gl_hash_table; -static void gfs2_glock_dealloc(struct rcu_head *rcu) +void gfs2_glock_free(struct gfs2_glock *gl) { - struct gfs2_glock *gl = container_of(rcu, struct gfs2_glock, gl_rcu); + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; if (gl->gl_ops->go_flags & GLOF_ASPACE) { kmem_cache_free(gfs2_glock_aspace_cachep, gl); @@ -90,13 +90,6 @@ static void gfs2_glock_dealloc(struct rcu_head *rcu) kfree(gl->gl_lksb.sb_lvbptr); kmem_cache_free(gfs2_glock_cachep, gl); } -} - -void gfs2_glock_free(struct gfs2_glock *gl) -{ - struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; - - call_rcu(&gl->gl_rcu, gfs2_glock_dealloc); if (atomic_dec_and_test(&sdp->sd_glock_disposal)) wake_up(&sdp->sd_glock_wait); } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 4a9077ec931366df03a96efa6491befb800ee4f5..be519416c11231ffe06a2bc12c41ea1cebf4de2f 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -367,7 +367,6 @@ struct gfs2_glock { loff_t end; } gl_vm; }; - struct rcu_head gl_rcu; struct rhash_head gl_node; }; diff --git a/fs/internal.h b/fs/internal.h index 1b93a3929b16ed4b78441f590fefc2a5984441bb..6387b35a1c0d13b0aa13fafff5d1889bac580038 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -153,29 +153,3 @@ extern void mnt_pin_kill(struct mount *m); * fs/nsfs.c */ extern struct dentry_operations ns_dentry_operations; - -#ifdef CONFIG_FILE_TABLE_DEBUG -void global_filetable_print_warning_once(void); -void global_filetable_add(struct file *filp); -void global_filetable_del(struct file *filp); -void global_filetable_delayed_print(struct mount *mnt); - -#else /* i.e NOT CONFIG_FILE_TABLE_DEBUG */ - -static inline void global_filetable_print_warning_once(void) -{ -} - -static inline void global_filetable_add(struct file *filp) -{ -} - -static inline void global_filetable_del(struct file *filp) -{ -} - -static inline void global_filetable_delayed_print(struct mount *mnt) -{ -} - -#endif /* CONFIG_FILE_TABLE_DEBUG */ diff --git a/fs/mount.h b/fs/mount.h index 37c64bbe840c6a8426f651ba3866bd028071d8c5..13a4ebbbaa74cbc6d55b6254da08448ea08d31dc 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -57,7 +57,6 @@ struct mount { struct mnt_namespace *mnt_ns; /* containing namespace */ struct mountpoint *mnt_mp; /* where is it mounted */ struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */ - struct list_head mnt_umounting; /* list entry for umount propagation */ #ifdef CONFIG_FSNOTIFY struct hlist_head mnt_fsnotify_marks; __u32 mnt_fsnotify_mask; diff --git a/fs/namei.c b/fs/namei.c index b5dfe2c5b51e0efc9c2292c5703caa2b2b833dad..816b6e8e934ef175d47ce2682c31cfce64bfca15 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3379,8 +3379,6 @@ out2: error = -ESTALE; } file = ERR_PTR(error); - } else { - global_filetable_add(file); } return file; } diff --git a/fs/namespace.c b/fs/namespace.c index f32450c3e72ccf018c986d0f01a4e28e44db3e0d..a22959c973842fd6d964a5429ad4707f0fe263a5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -237,7 +237,6 @@ static struct mount *alloc_vfsmnt(const char *name) INIT_LIST_HEAD(&mnt->mnt_slave_list); INIT_LIST_HEAD(&mnt->mnt_slave); INIT_HLIST_NODE(&mnt->mnt_mp_list); - INIT_LIST_HEAD(&mnt->mnt_umounting); #ifdef CONFIG_FSNOTIFY INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); #endif @@ -1596,8 +1595,6 @@ static int do_umount(struct mount *mnt, int flags) } unlock_mount_hash(); namespace_unlock(); - if (retval == -EBUSY) - global_filetable_delayed_print(mnt); return retval; } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8e425f2c5ddd5451d9e3761794f30b5d7b076df8..4e3679b25b9b5849436eb1ca2b2366a88c601f59 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2188,6 +2188,8 @@ static int nfs4_opendata_access(struct rpc_cred *cred, if ((mask & ~cache.mask & (MAY_READ | MAY_EXEC)) == 0) return 0; + /* even though OPEN succeeded, access is denied. Close the file */ + nfs4_close_state(state, fmode); return -EACCES; } diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index acebc350e98dd358959bafd463da8f9b46891b01..709fbbd44c65366ce1e31aebce0904b5966d53a6 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -2070,13 +2070,13 @@ unlock: spin_unlock(&o2hb_live_lock); } -static ssize_t o2hb_heartbeat_group_dead_threshold_show(struct config_item *item, +static ssize_t o2hb_heartbeat_group_threshold_show(struct config_item *item, char *page) { return sprintf(page, "%u\n", o2hb_dead_threshold); } -static ssize_t o2hb_heartbeat_group_dead_threshold_store(struct config_item *item, +static ssize_t o2hb_heartbeat_group_threshold_store(struct config_item *item, const char *page, size_t count) { unsigned long tmp; @@ -2125,11 +2125,11 @@ static ssize_t o2hb_heartbeat_group_mode_store(struct config_item *item, } -CONFIGFS_ATTR(o2hb_heartbeat_group_, dead_threshold); +CONFIGFS_ATTR(o2hb_heartbeat_group_, threshold); CONFIGFS_ATTR(o2hb_heartbeat_group_, mode); static struct configfs_attribute *o2hb_heartbeat_group_attrs[] = { - &o2hb_heartbeat_group_attr_dead_threshold, + &o2hb_heartbeat_group_attr_threshold, &o2hb_heartbeat_group_attr_mode, NULL, }; diff --git a/fs/open.c b/fs/open.c index 1fd96c5d3895fa5bb18399fdf7d4ee4b6dfe3a8d..e70cca15c976108e2a384f83fa6798a4fbc300b3 100644 --- a/fs/open.c +++ b/fs/open.c @@ -898,12 +898,6 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o int lookup_flags = 0; int acc_mode; - /* - * Clear out all open flags we don't know about so that we don't report - * them in fcntl(F_GETFD) or similar interfaces. - */ - flags &= VALID_OPEN_FLAGS; - if (flags & (O_CREAT | __O_TMPFILE)) op->mode = (mode & S_IALLUGO) | S_IFREG; else diff --git a/fs/pnode.c b/fs/pnode.c index ddb846f878b8a015414293019fd6d7b5a7ec735b..e4e428d621e9ff55280a329a5d478e0b5cba84a2 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -24,11 +24,6 @@ static inline struct mount *first_slave(struct mount *p) return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave); } -static inline struct mount *last_slave(struct mount *p) -{ - return list_entry(p->mnt_slave_list.prev, struct mount, mnt_slave); -} - static inline struct mount *next_slave(struct mount *p) { return list_entry(p->mnt_slave.next, struct mount, mnt_slave); @@ -169,19 +164,6 @@ static struct mount *propagation_next(struct mount *m, } } -static struct mount *skip_propagation_subtree(struct mount *m, - struct mount *origin) -{ - /* - * Advance m such that propagation_next will not return - * the slaves of m. - */ - if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) - m = last_slave(m); - - return m; -} - static struct mount *next_group(struct mount *m, struct mount *origin) { while (1) { @@ -433,104 +415,65 @@ void propagate_mount_unlock(struct mount *mnt) } } -static void umount_one(struct mount *mnt, struct list_head *to_umount) +/* + * Mark all mounts that the MNT_LOCKED logic will allow to be unmounted. + */ +static void mark_umount_candidates(struct mount *mnt) { - CLEAR_MNT_MARK(mnt); - mnt->mnt.mnt_flags |= MNT_UMOUNT; - list_del_init(&mnt->mnt_child); - list_del_init(&mnt->mnt_umounting); - list_move_tail(&mnt->mnt_list, to_umount); + struct mount *parent = mnt->mnt_parent; + struct mount *m; + + BUG_ON(parent == mnt); + + for (m = propagation_next(parent, parent); m; + m = propagation_next(m, parent)) { + struct mount *child = __lookup_mnt(&m->mnt, + mnt->mnt_mountpoint); + if (!child || (child->mnt.mnt_flags & MNT_UMOUNT)) + continue; + if (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m)) { + SET_MNT_MARK(child); + } + } } /* * NOTE: unmounting 'mnt' naturally propagates to all other mounts its * parent propagates to. */ -static bool __propagate_umount(struct mount *mnt, - struct list_head *to_umount, - struct list_head *to_restore) +static void __propagate_umount(struct mount *mnt) { - bool progress = false; - struct mount *child; + struct mount *parent = mnt->mnt_parent; + struct mount *m; - /* - * The state of the parent won't change if this mount is - * already unmounted or marked as without children. - */ - if (mnt->mnt.mnt_flags & (MNT_UMOUNT | MNT_MARKED)) - goto out; + BUG_ON(parent == mnt); - /* Verify topper is the only grandchild that has not been - * speculatively unmounted. - */ - list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { - if (child->mnt_mountpoint == mnt->mnt.mnt_root) - continue; - if (!list_empty(&child->mnt_umounting) && IS_MNT_MARKED(child)) + for (m = propagation_next(parent, parent); m; + m = propagation_next(m, parent)) { + struct mount *topper; + struct mount *child = __lookup_mnt(&m->mnt, + mnt->mnt_mountpoint); + /* + * umount the child only if the child has no children + * and the child is marked safe to unmount. + */ + if (!child || !IS_MNT_MARKED(child)) continue; - /* Found a mounted child */ - goto children; - } + CLEAR_MNT_MARK(child); - /* Mark mounts that can be unmounted if not locked */ - SET_MNT_MARK(mnt); - progress = true; - - /* If a mount is without children and not locked umount it. */ - if (!IS_MNT_LOCKED(mnt)) { - umount_one(mnt, to_umount); - } else { -children: - list_move_tail(&mnt->mnt_umounting, to_restore); - } -out: - return progress; -} - -static void umount_list(struct list_head *to_umount, - struct list_head *to_restore) -{ - struct mount *mnt, *child, *tmp; - list_for_each_entry(mnt, to_umount, mnt_list) { - list_for_each_entry_safe(child, tmp, &mnt->mnt_mounts, mnt_child) { - /* topper? */ - if (child->mnt_mountpoint == mnt->mnt.mnt_root) - list_move_tail(&child->mnt_umounting, to_restore); - else - umount_one(child, to_umount); - } - } -} + /* If there is exactly one mount covering all of child + * replace child with that mount. + */ + topper = find_topper(child); + if (topper) + mnt_change_mountpoint(child->mnt_parent, child->mnt_mp, + topper); -static void restore_mounts(struct list_head *to_restore) -{ - /* Restore mounts to a clean working state */ - while (!list_empty(to_restore)) { - struct mount *mnt, *parent; - struct mountpoint *mp; - - mnt = list_first_entry(to_restore, struct mount, mnt_umounting); - CLEAR_MNT_MARK(mnt); - list_del_init(&mnt->mnt_umounting); - - /* Should this mount be reparented? */ - mp = mnt->mnt_mp; - parent = mnt->mnt_parent; - while (parent->mnt.mnt_flags & MNT_UMOUNT) { - mp = parent->mnt_mp; - parent = parent->mnt_parent; + if (list_empty(&child->mnt_mounts)) { + list_del_init(&child->mnt_child); + child->mnt.mnt_flags |= MNT_UMOUNT; + list_move_tail(&child->mnt_list, &mnt->mnt_list); } - if (parent != mnt->mnt_parent) - mnt_change_mountpoint(parent, mp, mnt); - } -} - -static void cleanup_umount_visitations(struct list_head *visited) -{ - while (!list_empty(visited)) { - struct mount *mnt = - list_first_entry(visited, struct mount, mnt_umounting); - list_del_init(&mnt->mnt_umounting); } } @@ -544,69 +487,12 @@ static void cleanup_umount_visitations(struct list_head *visited) int propagate_umount(struct list_head *list) { struct mount *mnt; - LIST_HEAD(to_restore); - LIST_HEAD(to_umount); - LIST_HEAD(visited); - - /* Find candidates for unmounting */ - list_for_each_entry_reverse(mnt, list, mnt_list) { - struct mount *parent = mnt->mnt_parent; - struct mount *m; - - /* - * If this mount has already been visited it is known that it's - * entire peer group and all of their slaves in the propagation - * tree for the mountpoint has already been visited and there is - * no need to visit them again. - */ - if (!list_empty(&mnt->mnt_umounting)) - continue; - - list_add_tail(&mnt->mnt_umounting, &visited); - for (m = propagation_next(parent, parent); m; - m = propagation_next(m, parent)) { - struct mount *child = __lookup_mnt(&m->mnt, - mnt->mnt_mountpoint); - if (!child) - continue; - - if (!list_empty(&child->mnt_umounting)) { - /* - * If the child has already been visited it is - * know that it's entire peer group and all of - * their slaves in the propgation tree for the - * mountpoint has already been visited and there - * is no need to visit this subtree again. - */ - m = skip_propagation_subtree(m, parent); - continue; - } else if (child->mnt.mnt_flags & MNT_UMOUNT) { - /* - * We have come accross an partially unmounted - * mount in list that has not been visited yet. - * Remember it has been visited and continue - * about our merry way. - */ - list_add_tail(&child->mnt_umounting, &visited); - continue; - } - - /* Check the child and parents while progress is made */ - while (__propagate_umount(child, - &to_umount, &to_restore)) { - /* Is the parent a umount candidate? */ - child = child->mnt_parent; - if (list_empty(&child->mnt_umounting)) - break; - } - } - } - umount_list(&to_umount, &to_restore); - restore_mounts(&to_restore); - cleanup_umount_visitations(&visited); - list_splice_tail(&to_umount, list); + list_for_each_entry_reverse(mnt, list, mnt_list) + mark_umount_candidates(mnt); + list_for_each_entry(mnt, list, mnt_list) + __propagate_umount(mnt); return 0; } diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 7151ea428041d7c691f4983a7aeb62857790777a..2afbb82cd366ab7b23ebc2432c5660290b416b53 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -13,6 +13,7 @@ proc-$(CONFIG_TTY) += proc_tty.o proc-y += cmdline.o proc-y += consoles.o proc-y += cpuinfo.o +proc-y += cpu_time_stat.o proc-y += devices.o proc-y += interrupts.o proc-y += loadavg.o diff --git a/fs/proc/cpu_time_stat.c b/fs/proc/cpu_time_stat.c new file mode 100644 index 0000000000000000000000000000000000000000..d0ca09b4f70a58c08d8e9e5a57525b9c366bf4d5 --- /dev/null +++ b/fs/proc/cpu_time_stat.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef arch_irq_stat_cpu +#define arch_irq_stat_cpu(cpu) 0 +#endif +#ifndef arch_irq_stat +#define arch_irq_stat() 0 +#endif + +#ifdef arch_idle_time + +static cputime64_t get_idle_time(int cpu) +{ + cputime64_t idle; + + idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; + if (cpu_online(cpu) && !nr_iowait_cpu(cpu)) + idle += arch_idle_time(cpu); + return idle; +} + +static cputime64_t get_iowait_time(int cpu) +{ + cputime64_t iowait; + + iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT]; + if (cpu_online(cpu) && nr_iowait_cpu(cpu)) + iowait += arch_idle_time(cpu); + return iowait; +} + +#else + +static u64 get_idle_time(int cpu) +{ + u64 idle, idle_time = -1ULL; + + if (cpu_online(cpu)) + idle_time = get_cpu_idle_time_us(cpu, NULL); + + if (idle_time == -1ULL) + /* !NO_HZ or cpu offline so we can rely on cpustat.idle */ + idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; + else + idle = usecs_to_cputime64(idle_time); + + return idle; +} + +static u64 get_iowait_time(int cpu) +{ + u64 iowait, iowait_time = -1ULL; + + if (cpu_online(cpu)) + iowait_time = get_cpu_iowait_time_us(cpu, NULL); + + if (iowait_time == -1ULL) + /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */ + iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT]; + else + iowait = usecs_to_cputime64(iowait_time); + + return iowait; +} + +#endif + +static int show_cpu_time_stat(struct seq_file *p, void *v) +{ + int i, j; + u64 user, nice, system, idle, iowait, irq, softirq, steal; + u64 guest, guest_nice; + u64 sum = 0; + u64 sum_softirq = 0; + unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; + + user = nice = system = idle = iowait = + irq = softirq = steal = 0; + guest = guest_nice = 0; + + for_each_possible_cpu(i) { + user += kcpustat_cpu(i).cpustat[CPUTIME_USER]; + nice += kcpustat_cpu(i).cpustat[CPUTIME_NICE]; + system += kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]; + idle += get_idle_time(i); + iowait += get_iowait_time(i); + irq += kcpustat_cpu(i).cpustat[CPUTIME_IRQ]; + softirq += kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]; + steal += kcpustat_cpu(i).cpustat[CPUTIME_STEAL]; + guest += kcpustat_cpu(i).cpustat[CPUTIME_GUEST]; + guest_nice += kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE]; + sum += kstat_cpu_irqs_sum(i); + sum += arch_irq_stat_cpu(i); + + for (j = 0; j < NR_SOFTIRQS; j++) { + unsigned int softirq_stat = kstat_softirqs_cpu(j, i); + + per_softirq_sums[j] += softirq_stat; + sum_softirq += softirq_stat; + } + } + sum += arch_irq_stat(); + + seq_puts(p, "cpu "); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(user)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(nice)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(system)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(idle)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(iowait)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(irq)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(softirq)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(steal)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest_nice)); + seq_putc(p, '\n'); + + for_each_possible_cpu(i) { + /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ + user = kcpustat_cpu(i).cpustat[CPUTIME_USER]; + nice = kcpustat_cpu(i).cpustat[CPUTIME_NICE]; + system = kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]; + idle = get_idle_time(i); + iowait = get_iowait_time(i); + irq = kcpustat_cpu(i).cpustat[CPUTIME_IRQ]; + softirq = kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]; + steal = kcpustat_cpu(i).cpustat[CPUTIME_STEAL]; + guest = kcpustat_cpu(i).cpustat[CPUTIME_GUEST]; + guest_nice = kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE]; + seq_printf(p, "cpu%d", i); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(user)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(nice)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(system)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(idle)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(iowait)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(irq)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(softirq)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(steal)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest)); + seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest_nice)); + seq_putc(p, '\n'); + } + return 0; +} + +static int cpu_time_stat_open(struct inode *inode, struct file *file) +{ + size_t size = 128 * (num_possible_cpus() + 1); + return single_open_size(file, show_cpu_time_stat, NULL, size); +} + +static const struct file_operations proc_cpu_time_stat_operations = { + .open = cpu_time_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init proc_cpu_time_stat_init(void) +{ + proc_create("cpu_time_stat", 0, NULL, &proc_cpu_time_stat_operations); + return 0; +} +fs_initcall(proc_cpu_time_stat_init); diff --git a/fs/proc/page.c b/fs/proc/page.c index 93484034a03d04c38cc5ff7779fb95e7611fbd09..618f7aee74cdcc2a057211c3d61f13d260d3cbfe 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index f6c512a550e575c1cbc6e0f7ea9f6430919d09ed..303f69e4ec18ef7095945e79acc0ded74e9bb089 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1401,6 +1401,11 @@ static int pagemap_open(struct inode *inode, struct file *file) { struct mm_struct *mm; + /* do not disclose physical addresses: attack vector */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + mm = proc_mem_open(inode, PTRACE_MODE_READ); if (IS_ERR(mm)) return PTR_ERR(mm); diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 6076c342dae6406266678a33fc5acda1e7247ac9..5b589babd771edaebbb8cf165701c3a0010d07ac 100644 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -17,6 +17,11 @@ * under the terms of the Apache 2.0 License OR version 2 of the GNU * General Public License. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "sdcardfs.h" #ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE @@ -224,6 +229,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) /* save current_cred and override it */ OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(inode)); + file->f_mode |= FMODE_NONMAPPABLE; file->private_data = kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); if (!SDCARDFS_F(file)) { @@ -398,6 +404,11 @@ out: return err; } +static struct file *sdcardfs_get_lower_file(struct file *f) +{ + return sdcardfs_lower_file(f); +} + const struct file_operations sdcardfs_main_fops = { .llseek = generic_file_llseek, .read = sdcardfs_read, @@ -414,6 +425,7 @@ const struct file_operations sdcardfs_main_fops = { .fasync = sdcardfs_fasync, .read_iter = sdcardfs_read_iter, .write_iter = sdcardfs_write_iter, + .get_lower_file = sdcardfs_get_lower_file, }; /* trimmed directory options */ @@ -430,4 +442,5 @@ const struct file_operations sdcardfs_dir_fops = { .flush = sdcardfs_flush, .fsync = sdcardfs_fsync, .fasync = sdcardfs_fasync, + .get_lower_file = sdcardfs_get_lower_file, }; diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 103dc45a131fc07545e61cce6add44624ae46e37..06fa3768bb0244ec4f7e578bbfc5f6e74e675eed 100644 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -17,6 +17,11 @@ * under the terms of the Apache 2.0 License OR version 2 of the GNU * General Public License. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "sdcardfs.h" #include @@ -93,7 +98,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, } current->fs = copied_fs; current->fs->umask = 0; - err = vfs_create2(lower_dentry_mnt, d_inode(lower_parent_dentry), lower_dentry, mode, want_excl); + err = vfs_create2(lower_dentry_mnt, lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); if (err) goto out; @@ -310,7 +315,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode } current->fs = copied_fs; current->fs->umask = 0; - err = vfs_mkdir2(lower_mnt, d_inode(lower_parent_dentry), lower_dentry, mode); + err = vfs_mkdir2(lower_mnt, lower_parent_dentry->d_inode, lower_dentry, mode); if (err) { unlock_dir(lower_parent_dentry); @@ -766,13 +771,19 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct * afterwards in the other cases: we fsstack_copy_inode_size from * the lower level. */ + if (current->mm) + down_write(¤t->mm->mmap_sem); if (ia->ia_valid & ATTR_SIZE) { err = inode_newsize_ok(&tmp, ia->ia_size); if (err) { + if (current->mm) + up_write(¤t->mm->mmap_sem); goto out; } truncate_setsize(inode, ia->ia_size); } + if (current->mm) + up_write(¤t->mm->mmap_sem); /* * mode change is for clearing setuid/setgid bits. Allow lower fs @@ -857,6 +868,8 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, goto out; sdcardfs_copy_and_fix_attrs(d_inode(dentry), d_inode(lower_path.dentry)); + fsstack_copy_inode_size(d_inode(dentry), + d_inode(lower_path.dentry)); err = sdcardfs_fillattr(mnt, d_inode(dentry), stat); stat->blocks = lower_stat.blocks; out: diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 676e394e07be4ae52ca6800524ef05892097817a..eb0a348e4ac2509b3ca2972fe2960543819ddec1 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -17,9 +17,15 @@ * under the terms of the Apache 2.0 License OR version 2 of the GNU * General Public License. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "sdcardfs.h" #include "linux/delay.h" +#include /* The dentry cache is just so we have properly sized dentries */ static struct kmem_cache *sdcardfs_dentry_cachep; @@ -114,6 +120,10 @@ struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, u /* if found a cached inode, then just return it (after iput) */ if (!(inode->i_state & I_NEW)) { iput(lower_inode); + /* There can only be one alias, as we don't permit hard links + * This ensures we do not keep stale dentries that would later + * cause confusion. */ + d_prune_aliases(inode); return inode; } @@ -244,6 +254,89 @@ static int sdcardfs_name_match(struct dir_context *ctx, const char *name, return 0; } +/* The dir context used by sdcardfs_lower_filldir() */ +struct sdcardfs_lower_getent_cb { + struct dir_context ctx; + loff_t pos; + const char *target; /* search target */ + int target_len; + char alias[NAME_MAX+1]; /* alias name found in lower dir */ + int alias_len; + int result; /* 0: found, -ENOENT: not found. */ +}; + +/* The filldir used by case insensitive search in sdcardfs_ci_path_lookup() */ +static int +sdcardfs_lower_filldir(struct dir_context *ctx, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct sdcardfs_lower_getent_cb *buf; + + buf = container_of(ctx, struct sdcardfs_lower_getent_cb, ctx); + + if (!buf->result) /* entry already found, skip search */ + return 0; + + buf->pos = buf->ctx.pos; + if (!strncasecmp(name, buf->target, namelen) && + namelen == buf->target_len) { + strlcpy(buf->alias, name, namelen + 1); + buf->alias_len = namelen; + buf->result = 0; /* 0: found matching entry */ + } + return 0; +} + +/* + * Case insentively lookup lower directory. + * + * @folder: path to the lower folder. + * @name: lookup name. + * @entry: path to the found entry. + * + * Returns: 0 (ok), -ENOENT (entry not found) + */ +static int sdcardfs_ci_path_lookup(struct path *folder, const char *name, + struct path *entry) +{ + int ret = 0; + struct file *filp; + loff_t last_pos; + struct sdcardfs_lower_getent_cb buf = { + .ctx.actor = sdcardfs_lower_filldir, + .ctx.pos = 0, + .pos = 0, + .target = name, + .alias_len = 0, + .result = -ENOENT + }; + + + buf.target_len = strlen(name); + + filp = dentry_open(folder, O_RDONLY | O_DIRECTORY, current_cred()); + + if (IS_ERR_OR_NULL(filp)) + return -ENOENT; + + while (ret >= 0) { + last_pos = filp->f_pos; + ret = iterate_dir(filp, &buf.ctx); + /* reaches end or found matching entry */ + if (last_pos == filp->f_pos || !buf.result) + break; + } + + filp_close(filp, NULL); + + if (!buf.result) + return vfs_path_lookup(folder->dentry, folder->mnt, buf.alias, + 0, entry); + else + return buf.result; + +} + /* * Main driver function for sdcardfs's lookup. * @@ -316,6 +409,36 @@ put_name: __putname(buffer.name); } + /* If the dentry was not found, and the intent is not rename file, + * try case insensitive search in lower parent directory. + */ + if ((err == -ENOENT) && !(flags & LOOKUP_RENAME_TARGET)) + err = sdcardfs_ci_path_lookup(lower_parent_path, name->name, &lower_path); +#if 0 + /* check for other cases */ + if (err == -ENOENT) { + struct dentry *child; + struct dentry *match = NULL; + spin_lock(&lower_dir_dentry->d_lock); + list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_child) { + if (child && child->d_inode) { + if (strcasecmp(child->d_name.name, name)==0) { + match = dget(child); + break; + } + } + } + spin_unlock(&lower_dir_dentry->d_lock); + if (match) { + err = vfs_path_lookup(lower_dir_dentry, + lower_dir_mnt, + match->d_name.name, 0, + &lower_path); + dput(match); + } + } +#endif + /* no error: handle positive dentries */ if (!err) { /* check if the dentry is an obb dentry diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 80825b28783651ccee7d6fbf80ed830e321826f5..3c5b51d49d21affe265e16b9b3941fa0dd25d27b 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -364,34 +364,41 @@ out: return err; } -struct sdcardfs_mount_private { - struct vfsmount *mnt; - const char *dev_name; - void *raw_data; -}; +/* A feature which supports mount_nodev() with options */ +static struct dentry *mount_nodev_with_options(struct vfsmount *mnt, + struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + int (*fill_super)(struct vfsmount *, struct super_block *, + const char *, void *, int)) -static int __sdcardfs_fill_super( - struct super_block *sb, - void *_priv, int silent) { - struct sdcardfs_mount_private *priv = _priv; + int error; + struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL); + + if (IS_ERR(s)) + return ERR_CAST(s); + + s->s_flags = flags; - return sdcardfs_read_super(priv->mnt, - sb, priv->dev_name, priv->raw_data, silent); + error = fill_super(mnt, s, dev_name, data, flags & MS_SILENT ? 1 : 0); + if (error) { + deactivate_locked_super(s); + return ERR_PTR(error); + } + s->s_flags |= MS_ACTIVE; + return dget(s->s_root); } static struct dentry *sdcardfs_mount(struct vfsmount *mnt, struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data) { - struct sdcardfs_mount_private priv = { - .mnt = mnt, - .dev_name = dev_name, - .raw_data = raw_data - }; - - return mount_nodev(fs_type, flags, - &priv, __sdcardfs_fill_super); + /* + * dev_name is a lower_path_name, + * raw_data is a option string. + */ + return mount_nodev_with_options(mnt, fs_type, flags, dev_name, + raw_data, sdcardfs_read_super); } static struct dentry *sdcardfs_mount_wrn(struct file_system_type *fs_type, @@ -416,7 +423,7 @@ void sdcardfs_kill_sb(struct super_block *sb) list_del(&sbi->list); mutex_unlock(&sdcardfs_super_list_lock); } - kill_anon_super(sb); + generic_shutdown_super(sb); } static struct file_system_type sdcardfs_fs_type = { diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index b3b95e2ae2ff40fd0837a2a9c41409c9125e4a6d..2eb66decc5abc4f38475cb666634cbe96568982d 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c @@ -121,12 +121,11 @@ static void squashfs_process_blocks(struct squashfs_read_request *req) if (req->data_processing == SQUASHFS_METADATA) { /* Extract the length of the metadata block */ - if (req->offset != msblk->devblksize - 1) { - length = le16_to_cpup((__le16 *) - (bh[0]->b_data + req->offset)); - } else { - length = (unsigned char)bh[0]->b_data[req->offset]; - length |= (unsigned char)bh[1]->b_data[0] << 8; + if (req->offset != msblk->devblksize - 1) + length = *((u16 *)(bh[0]->b_data + req->offset)); + else { + length = bh[0]->b_data[req->offset]; + length |= bh[1]->b_data[0] << 8; } req->compressed = SQUASHFS_COMPRESSED(length); req->data_processing = req->compressed ? SQUASHFS_DECOMPRESS @@ -212,8 +211,8 @@ static int bh_is_optional(struct squashfs_read_request *req, int idx) int start_idx, end_idx; struct squashfs_sb_info *msblk = req->sb->s_fs_info; - start_idx = (idx * msblk->devblksize - req->offset) >> PAGE_SHIFT; - end_idx = ((idx + 1) * msblk->devblksize - req->offset + 1) >> PAGE_SHIFT; + start_idx = (idx * msblk->devblksize - req->offset) / PAGE_CACHE_SIZE; + end_idx = ((idx + 1) * msblk->devblksize - req->offset + 1) / PAGE_CACHE_SIZE; if (start_idx >= req->output->pages) return 1; if (start_idx < 0) diff --git a/fs/xfs/kmem.c b/fs/xfs/kmem.c index 686ba6fb20ddc942638f6e698b98bf4c1bb8785f..bb38cbffd68ff41fce93f85c86f3f8caeda67f04 100644 --- a/fs/xfs/kmem.c +++ b/fs/xfs/kmem.c @@ -15,6 +15,11 @@ * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include diff --git a/fs/xfs/kmem.h b/fs/xfs/kmem.h index cc6b768fc068f4aa22e994724e9d91fe8698c8e2..dc5486f9b9b0e00c58e4d479ebd9e642c6a830c8 100644 --- a/fs/xfs/kmem.h +++ b/fs/xfs/kmem.h @@ -15,6 +15,11 @@ * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __XFS_SUPPORT_KMEM_H__ #define __XFS_SUPPORT_KMEM_H__ diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 36c7bacaf7f1101788d5aa40e546fb79682f2d31..f2399ba8dfdbc12cd35985b0fe11ece929074fe1 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -49,6 +49,11 @@ * Examples are: [__initramfs_start, __initramfs_end] for initramfs and * [__nosave_begin, __nosave_end] for the nosave data */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef LOAD_OFFSET #define LOAD_OFFSET 0 diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f710a7075c0ed18dcdbc5b815f05b97ba7fbd05f..6555fdbee88a9a52b93d7153f5bf77b05140e5b3 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -652,15 +652,12 @@ struct drm_encoder { * @pt_scan_info: PT scan info obtained from the VCDB of EDID * @it_scan_info: IT scan info obtained from the VCDB of EDID * @ce_scan_info: CE scan info obtained from the VCDB of EDID - * @color_enc_fmt: Colorimetry encoding formats of sink * @hdr_eotf: Electro optical transfer function obtained from HDR block * @hdr_metadata_type_one: Metadata type one obtained from HDR block * @hdr_max_luminance: desired max luminance obtained from HDR block * @hdr_avg_luminance: desired avg luminance obtained from HDR block * @hdr_min_luminance: desired min luminance obtained from HDR block * @hdr_supported: does the sink support HDR content - * @rgb_qs: does the sink declare RGB selectable quantization range - * @yuv_qs: does the sink declare YCC selectable quantization range * @edid_corrupt: indicates whether the last read EDID was corrupt * @debugfs_entry: debugfs directory for this connector * @state: current atomic state for this connector @@ -743,15 +740,12 @@ struct drm_connector { u8 pt_scan_info; u8 it_scan_info; u8 ce_scan_info; - u8 color_enc_fmt; u32 hdr_eotf; bool hdr_metadata_type_one; u32 hdr_max_luminance; u32 hdr_avg_luminance; u32 hdr_min_luminance; bool hdr_supported; - bool rgb_qs; - bool yuv_qs; /* Flag for raw EDID header corruption - used in Displayport * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6 */ diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index c0884e120041b779302fcaba5b1ba44a4a5e1bab..69cb2ba371163d396ca4b7be82ae993861bafd6c 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -214,15 +214,6 @@ struct detailed_timing { #define DRM_EDID_YCBCR420_DC_36 (1 << 1) #define DRM_EDID_YCBCR420_DC_30 (1 << 0) -#define DRM_EDID_COLORIMETRY_xvYCC_601 (1 << 0) -#define DRM_EDID_COLORIMETRY_xvYCC_709 (1 << 1) -#define DRM_EDID_COLORIMETRY_sYCC_601 (1 << 2) -#define DRM_EDID_COLORIMETRY_ADBYCC_601 (1 << 3) -#define DRM_EDID_COLORIMETRY_ADB_RGB (1 << 4) -#define DRM_EDID_COLORIMETRY_BT2020_CYCC (1 << 5) -#define DRM_EDID_COLORIMETRY_BT2020_YCC (1 << 6) -#define DRM_EDID_COLORIMETRY_BT2020_RGB (1 << 7) - /* ELD Header Block */ #define DRM_ELD_HEADER_BLOCK_SIZE 4 diff --git a/include/dt-bindings/clock/msm-clocks-8998.h b/include/dt-bindings/clock/msm-clocks-8998.h index 67e47c46e09a52977766d1a325ed9117a1f86cc5..cd36374a04a757fbb827906ee9e744873a8bf24f 100644 --- a/include/dt-bindings/clock/msm-clocks-8998.h +++ b/include/dt-bindings/clock/msm-clocks-8998.h @@ -443,11 +443,6 @@ #define clk_dsi0pll_pclk_src 0x5efd85d4 #define clk_dsi0pll_pclk_src_mux 0x84b14663 #define clk_dsi0pll_post_bit_div 0xf46dcf27 -#define clk_dsi0pll_pll_out_div1 0xeda5b7fe -#define clk_dsi0pll_pll_out_div2 0x97fa476d -#define clk_dsi0pll_pll_out_div4 0x90a98ce0 -#define clk_dsi0pll_pll_out_div8 0x9d9d85cf -#define clk_dsi0pll_pll_out_mux 0x179c27ca #define clk_dsi0pll_post_vco_mux 0xfaf9bd1f #define clk_dsi0pll_post_vco_div1 0xabb50b2a #define clk_dsi0pll_post_vco_div4 0xbe51c091 @@ -460,11 +455,6 @@ #define clk_dsi1pll_pclk_src 0xeddcd80e #define clk_dsi1pll_pclk_src_mux 0x3651feb3 #define clk_dsi1pll_post_bit_div 0x712f0260 -#define clk_dsi1pll_pll_out_div8 0x87628ddb -#define clk_dsi1pll_pll_out_div4 0x0d9a384b -#define clk_dsi1pll_pll_out_div2 0x0c9b5748 -#define clk_dsi1pll_pll_out_div1 0x3193164e -#define clk_dsi1pll_pll_out_mux 0x171bf8fd #define clk_dsi1pll_post_vco_mux 0xc6a90d20 #define clk_dsi1pll_post_vco_div1 0x6f47ca7d #define clk_dsi1pll_post_vco_div4 0x90628974 diff --git a/include/dt-bindings/mfd/qcom-rpm.h b/include/dt-bindings/mfd/qcom-rpm.h index 13a9d4bf2662a1fa418f7ee358ba2eb929241a11..9d6189107a7c51d7d5977139f95def379f0a002f 100644 --- a/include/dt-bindings/mfd/qcom-rpm.h +++ b/include/dt-bindings/mfd/qcom-rpm.h @@ -1,6 +1,11 @@ /* * This header provides constants for the Qualcomm RPM bindings. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _DT_BINDINGS_MFD_QCOM_RPM_H #define _DT_BINDINGS_MFD_QCOM_RPM_H diff --git a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h index 64e2dc7183f33a8df2f5ad079ebc37faa7a320bf..119aaa7cb5546e924af31026eb43f4615c6d2a1d 100644 --- a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h +++ b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h @@ -1,6 +1,11 @@ /* * This header provides constants for the Qualcomm PMIC GPIO binding. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _DT_BINDINGS_PINCTRL_QCOM_PMIC_GPIO_H #define _DT_BINDINGS_PINCTRL_QCOM_PMIC_GPIO_H diff --git a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h index a15c1704d0ec6175878640bbba81baae8d5a64bc..560a8fd78644c77725f27a15d85cf3120aa40f92 100644 --- a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h +++ b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h @@ -2,6 +2,11 @@ * This header provides constants for the Qualcomm PMIC's * Multi-Purpose Pin binding. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _DT_BINDINGS_PINCTRL_QCOM_PMIC_MPP_H #define _DT_BINDINGS_PINCTRL_QCOM_PMIC_MPP_H diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h index fb790b8449c1ffba36c740f3001777fa973a11d4..50cf74521904ceace125edf06eddff8c2a2c24d6 100644 --- a/include/linux/bitrev.h +++ b/include/linux/bitrev.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _LINUX_BITREV_H #define _LINUX_BITREV_H diff --git a/include/linux/clearpad.h b/include/linux/clearpad.h new file mode 100644 index 0000000000000000000000000000000000000000..48ba73ddfa251625839e1cee7dd93505d4f236be --- /dev/null +++ b/include/linux/clearpad.h @@ -0,0 +1,124 @@ +/* include/linux/clearpad.h + * + * Author: Courtney Cavin + * Yusuke Yoshimura + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_CLEARPAD_H +#define __LINUX_CLEARPAD_H + +#include +#include +#include + +#define CLEARPAD_NAME "clearpad" +#define CLEARPADI2C_NAME "clearpad-i2c" +#define CLEARPAD_RMI_DEV_NAME "clearpad-rmi-dev" + +#define SYN_PCA_BLOCK_SIZE 16 +#define SYN_PCA_BLOCK_NUMBER_MAX 31 + +enum clearpad_funcarea_kind_e { + SYN_FUNCAREA_INSENSIBLE, + SYN_FUNCAREA_POINTER, + SYN_FUNCAREA_BUTTON, + SYN_FUNCAREA_END, +}; + +enum clearpad_flip_config_e { + SYN_FLIP_NONE, + SYN_FLIP_X, + SYN_FLIP_Y, + SYN_FLIP_XY, +}; + +enum clearpad_infomation_attribute_kind_e { + PCA_DATA = 0x00, + PCA_IC = 0x01, + PCA_CHIP = 0x03, + PCA_MODULE = 0x05, +}; + +enum clearpad_infomation_kind_e { + PCA_NO_USE = 0x00, + PCA_FW_INFO = 0x02, +}; + +struct clearpad_area_t { + int x1; + int y1; + int x2; + int y2; +}; + +struct clearpad_funcarea_t { + struct clearpad_area_t original; /* actual area */ + struct clearpad_area_t extension; /* extended area to track events */ + enum clearpad_funcarea_kind_e func; + void *data; +}; + +struct clearpad_pointer_data_t { + int offset_x; + int offset_y; +}; + +struct clearpad_button_data_t { + int code; + bool down; + bool down_report; +}; + +struct clearpad_platform_data_t { + int irq_gpio; + u32 irq_gpio_flags; + char *symlink_name; + bool watchdog_enable; + int watchdog_poll_t_ms; +}; + +struct clearpad_bus_data_t { + __u16 bustype; + struct device *dev; + struct device_node *of_node; + int (*set_page)(struct device *dev, u8 page); + int (*read)(struct device *dev, u16 addr, u8 *buf, u8 len); + int (*write)(struct device *dev, u16 addr, const u8 *buf, u8 len); + int (*read_block)(struct device *dev, u16 addr, u8 *buf, int len); + int (*write_block)(struct device *dev, u16 addr, const u8 *buf, + int len); +}; + +struct clearpad_data_t { + struct clearpad_platform_data_t *pdata; + struct clearpad_bus_data_t *bdata; + int probe_retry; +#ifdef CONFIG_TOUCHSCREEN_CLEARPAD_RMI_DEV + struct platform_device *rmi_dev; +#endif +}; + +struct clearpad_ioctl_pca_info { + u16 block_pos; + u8 data[SYN_PCA_BLOCK_SIZE]; +}; + +#define SYN_PCA_IOCTL_MAGIC 0xCC +#define SYN_PCA_IOCTL_GET \ + _IOWR(SYN_PCA_IOCTL_MAGIC, 1, struct clearpad_ioctl_pca_info *) +#define SYN_PCA_IOCTL_SET \ + _IOW(SYN_PCA_IOCTL_MAGIC, 2, struct clearpad_ioctl_pca_info *) + +#endif diff --git a/include/linux/console.h b/include/linux/console.h index ea731af2451ee3607c16fda14d50fa684a54f03b..1a82576a21ce99c7a358149d0b30dcb43fae79a4 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -10,6 +10,11 @@ * Changed: * 10-Mar-94: Arno Griffioen: Conversion for vt100 emulator port from PC LINUX */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _LINUX_CONSOLE_H_ #define _LINUX_CONSOLE_H_ 1 @@ -168,6 +173,7 @@ extern bool console_suspend_enabled; /* Suspend and resume console messages over PM events */ extern void suspend_console(void); +extern int is_console_suspended(void); extern void resume_console(void); int mda_console_init(void); diff --git a/include/linux/coredump.h b/include/linux/coredump.h index 28ffa94aed6b85d10531e7dc11864f9ebc8701f4..d016a121a8c46492bd6feea5b093dcea9bf27933 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -14,7 +14,6 @@ struct coredump_params; extern int dump_skip(struct coredump_params *cprm, size_t nr); extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr); extern int dump_align(struct coredump_params *cprm, int align); -extern void dump_truncate(struct coredump_params *cprm); #ifdef CONFIG_COREDUMP extern void do_coredump(const siginfo_t *siginfo); #else diff --git a/include/linux/cpu.h b/include/linux/cpu.h index a3bcdfbef9ca8535004e77ee5fe9f0b80e631ea8..a157a69097b5d0e4ab4aa0cc84a76f139c31dd51 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -234,7 +234,6 @@ extern struct bus_type cpu_subsys; extern void cpu_hotplug_begin(void); extern void cpu_hotplug_done(void); extern void get_online_cpus(void); -extern void cpu_hotplug_mutex_held(void); extern void put_online_cpus(void); extern void cpu_hotplug_disable(void); extern void cpu_hotplug_enable(void); @@ -257,7 +256,6 @@ static inline void cpu_hotplug_done(void) {} #define cpu_hotplug_enable() do { } while (0) #define hotcpu_notifier(fn, pri) do { (void)(fn); } while (0) #define __hotcpu_notifier(fn, pri) do { (void)(fn); } while (0) -#define cpu_hotplug_mutex_held() do { } while (0) /* These aren't inline functions due to a GCC bug. */ #define register_hotcpu_notifier(nb) ({ (void)(nb); 0; }) #define __register_hotcpu_notifier(nb) ({ (void)(nb); 0; }) diff --git a/include/linux/crash_notes.h b/include/linux/crash_notes.h new file mode 100644 index 0000000000000000000000000000000000000000..63fc0889ec445f93fdba5c0ce67d8e94d322b33a --- /dev/null +++ b/include/linux/crash_notes.h @@ -0,0 +1,37 @@ +/* include/linux/crash_notes.h + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __CRASH_NOTES_H +#define __CRASH_NOTES_H + +#ifdef CONFIG_CRASH_NOTES +#include + +enum crash_note_save_type { + CRASH_NOTE_INIT, + CRASH_NOTE_STOPPING, + CRASH_NOTE_CRASHING +}; + +extern void crash_notes_save_cpus(void); + +#ifndef CONFIG_ARCH_HAS_CRASH_NOTES +static inline void crash_notes_save_regs(struct pt_regs *regs) { } +#endif + +#else /*!CONFIG_CRASH_NOTES*/ +static inline void crash_notes_save_cpus(void) { } +#endif /*CONFIG_CRASH_NOTES*/ +#endif /*__CRASH_NOTES_H*/ diff --git a/include/linux/cxd224x.h b/include/linux/cxd224x.h new file mode 100644 index 0000000000000000000000000000000000000000..e3b8d01ae32f8e4c7088af353eae36e318282498 --- /dev/null +++ b/include/linux/cxd224x.h @@ -0,0 +1,21 @@ +/* include/linux/cxd224x.h + * + * Copyright (C) 2012 Sony Corporation. + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ + +#ifndef _CXD224X_H +#define _CXD224X_H + +#define CXD224X_DEVICE_NAME "cxd224x-i2c" + +struct cxd224x_platform_data { + unsigned int irq_gpio; + unsigned int wake_gpio; +}; + +#endif diff --git a/include/linux/device.h b/include/linux/device.h index 30c52d70c86dc002e39d192bb96eb469beb2317b..4b4e2d5ce6e70c2ffadb9796e934fda50e936eff 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -368,7 +368,6 @@ int subsys_virtual_register(struct bus_type *subsys, * @suspend: Used to put the device to sleep mode, usually to a low power * state. * @resume: Used to bring the device from the sleep mode. - * @shutdown: Called at shut-down time to quiesce the device. * @ns_type: Callbacks so sysfs can detemine namespaces. * @namespace: Namespace of the device belongs to this class. * @pm: The default device power management operations of this class. @@ -397,7 +396,6 @@ struct class { int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); - int (*shutdown)(struct device *dev); const struct kobj_ns_type_operations *ns_type; const void *(*namespace)(struct device *dev); diff --git a/include/linux/extcon.h b/include/linux/extcon.h index e1360198955acd7913e47b472dcb44d963f616d6..54034e058b8f7d304b5960e9b74df7f20800e40f 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -22,6 +22,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __LINUX_EXTCON_H__ #define __LINUX_EXTCON_H__ @@ -72,7 +77,10 @@ #define EXTCON_JIG 61 #define EXTCON_MECHANICAL 62 -#define EXTCON_NUM 63 +/* Somc Extention */ +#define EXTCON_VBUS_DROP 63 + +#define EXTCON_NUM 64 struct extcon_cable; diff --git a/include/linux/fb.h b/include/linux/fb.h index 87942d80a46519b1dc38f64b6d857fd1db88099c..9104bb301ac9bdceec557be54fa2ee78770595e6 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _LINUX_FB_H #define _LINUX_FB_H @@ -163,6 +168,13 @@ struct fb_cursor_user { /* A hardware display blank revert early change occured */ #define FB_R_EARLY_EVENT_BLANK 0x11 +#ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL +/* A hardware display extension blank early change occurred */ +#define FB_EXT_EARLY_EVENT_BLANK 0xF0 +/* A hardware display extension blank change occurred */ +#define FB_EXT_EVENT_BLANK 0xF1 +#endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ + struct fb_event { struct fb_info *info; void *data; diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h index 1b48d9c9a5613cc1b619444e2046c36dcfeda872..76ce329e656d1eaca5a6d6792f97d3c067fa37c6 100644 --- a/include/linux/fcntl.h +++ b/include/linux/fcntl.h @@ -3,12 +3,6 @@ #include -/* list of all valid flags for the open/openat flags argument: */ -#define VALID_OPEN_FLAGS \ - (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ - O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \ - FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) #ifndef force_o_largefile #define force_o_largefile() (BITS_PER_LONG != 32) diff --git a/include/linux/fs.h b/include/linux/fs.h index df1171bada015382c736aa490fa18e6708dd35a1..88cc1ef245756142f2e804099f501c80b1bf3c50 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -138,6 +138,9 @@ typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate); /* Has write method(s) */ #define FMODE_CAN_WRITE ((__force fmode_t)0x40000) +/* File hasn't page cache and can't be mmaped, for stackable filesystem */ +#define FMODE_NONMAPPABLE ((__force fmode_t)0x400000) + /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) @@ -912,10 +915,6 @@ struct file { struct list_head f_tfile_llink; #endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping; - -#ifdef CONFIG_FILE_TABLE_DEBUG - struct hlist_node f_hash; -#endif /* #ifdef CONFIG_FILE_TABLE_DEBUG */ } __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */ struct file_handle { @@ -1691,6 +1690,7 @@ struct file_operations { #ifndef CONFIG_MMU unsigned (*mmap_capabilities)(struct file *); #endif + struct file* (*get_lower_file)(struct file *f); }; struct inode_operations { diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index ecb080d6ff42077513f03b95537dc108bded9e07..87d5a3ff2c7d683bf6e448dbb9fd69da834c4dae 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _LINUX_HUGE_MM_H #define _LINUX_HUGE_MM_H diff --git a/include/linux/incell.h b/include/linux/incell.h new file mode 100644 index 0000000000000000000000000000000000000000..3cfa3fe26e9df5613fe27ad4c701025c7ed5e2f4 --- /dev/null +++ b/include/linux/incell.h @@ -0,0 +1,103 @@ +/* include/linux/incell.h + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __INCELL_H__ +#define __INCELL_H__ + +#include + +#define INCELL_OK ((int)0) + +/* We need to discuss the bellow error name */ +#define INCELL_ERROR ((int)(-1)) + +#define INCELL_ALREADY_LOCKED ((int)(-2)) +#define INCELL_ALREADY_UNLOCKED ((int)(-3)) +#define INCELL_EBUSY ((int)(-4)) +#define INCELL_EALREADY ((int)(-5)) + +#define INCELL_POWER_ON ((bool)true) +#define INCELL_POWER_OFF ((bool)false) +#define INCELL_FORCE ((bool)true) +#define INCELL_UNFORCE ((bool)false) + +typedef struct { + bool touch_power; + bool display_power; +} incell_pw_status; + +typedef enum { + INCELL_DISPLAY_HW_RESET, + INCELL_DISPLAY_OFF, + INCELL_DISPLAY_ON, +} incell_intf_mode; + +typedef enum { + INCELL_DISPLAY_POWER_UNLOCK, + INCELL_DISPLAY_POWER_LOCK, +} incell_pw_lock; + +typedef enum { + INCELL_DISPLAY_EWU_DISABLE, + INCELL_DISPLAY_EWU_ENABLE, +} incell_ewu_mode; + +/** + * @brief Get incell power status. + * @param[in] power_status : touch_power/display_power
+ * INCELL_POWER_ON : Power on state
+ * INCELL_POWER_OFF : Power off state. + * @return INCELL_OK : Get power status successfully
+ * INCELL_ERROR : Failed to get power status. + */ +int incell_get_power_status(incell_pw_status *power_status); + +/** + * @brief Display control mode. + * @param[in] mode : INCELL_DISPLAY_HW_RESET(execute on/off)
+ * INCELL_DISPLAY_OFF(touch is working)
+ * INCELL_DISPLAY_ON(only LCD on) + * @param[in] force : INCELL_FORCE - Forcibly execute an interface
+ * INCELL_UNFORCE - Depending power lock or not. + * @return INCELL_OK : success
+ * INCELL_ERROR : error detected
+ * INCELL_EBUSY : try lock failed. + * @attention You cannot call this function from same fb_blank context. + */ +int incell_control_mode(incell_intf_mode mode, bool force); + +/** + * @brief LCD/Touch Power lock control. + * @param[in] lock : INCELL_DISPLAY_POWER_UNLOCK(not keep power supply)
+ * INCELL_DISPLAY_POWER_LOCK(keep power supply)
+ * @param[out] power_status : return power state of incell_pw_status + * by calling incell_get_power_status function. + * @return INCELL_OK : success
+ * INCELL_ERROR : error detected
+ * INCELL_ALREADY_LOCKED : Already power locked
+ * INCELL_ALREADY_UNLOCKED : Already power unlocked. + */ +int incell_power_lock_ctrl(incell_pw_lock lock, + incell_pw_status *power_status); + +/** + * @brief Easy wake up mode (EWU) control. + * @param[in] ewu : INCELL_DISPLAY_EWU_ENABLE (EWU mode enabled)
+ * INCELL_DISPLAY_EWU_DISABLE (EWU mode disabled) + */ +void incell_ewu_mode_ctrl(incell_ewu_mode ewu); + +#endif /* __INCELL_H__ */ + diff --git a/include/linux/input/adux1050.h b/include/linux/input/adux1050.h new file mode 100644 index 0000000000000000000000000000000000000000..58b4aa6c776219093d31d796e13357dbb8106f72 --- /dev/null +++ b/include/linux/input/adux1050.h @@ -0,0 +1,605 @@ +/* + * include/linux/input/adux1050.h + * ADUX1050 controller driver header. + * This file is the header file for the ADUX1050 driver source. + * It also has chip structure prototype and the platform data prototype. + * + * Copyright 2016 Analog Devices Inc. + * + * Licensed under the GPL version 2 or later. + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_INPUT_ADUX1050_H__ +#define __LINUX_INPUT_ADUX1050_H__ + +/* + * REGISTER BASED DEFINES associated with the driver + */ +/* Device ID Register Address */ +#define DEV_ID_REG (0x0) +/* Power and control Register */ +#define CTRL_REG (0x1) +/* Conversion time control Register */ +#define CONV_TIME_CTRL_REG (0x2) +/* Filter and interrupt control */ +#define INT_CTRL_REG (0x3) +/* Conversion and sync input config register */ +#define CONV_SYNC_CFG_REG (0x4) +/* Baseline / Ambient control Register Address */ +#define BASELINE_CTRL_REG (0x5) +/* Stage 0 configuration register */ +#define CONFIG_STG0_REG (0x6) +/* Stage 0 high threshold register */ +#define HIGH_TH_STG0_REG (0x7) +/* Stage 0 low threshold register */ +#define LOW_TH_STG0_REG (0x8) +/* DAC offset for stage 0 */ +#define OFFSET_DAC_STG0_REG (0x9) +/* Hysteresis settings for stage 0 */ +#define HYS_STG0_REG (0xA) +/* Interrupt status register */ +#define INT_STATUS_REG (0x70) +/* Stage 0 CDC result data register */ +#define RESULT_STG0_REG (0x71) +/* Peak to peak noise mesurement result register */ +#define PK2P_STG0_REG (0x75) +/* Register address of stage 0 baseline */ +#define BASELINE_STG0_REG (0x79) +/* Register address of stage 1 baseline */ +#define BASELINE_STG1_REG (0x7A) +/* Register address of stage 2 baseline */ +#define BASELINE_STG2_REG (0x7B) +/* Register address of stage 3 baseline */ +#define BASELINE_STG3_REG (0x7C) +/* Proximity status of all stages */ +#define PROX_STATUS_REG (0x7D) +/* Lowest Read/Write accessible register */ +#define HIGHEST_WR_ACCESS (0x19) +/* Highest accesible register */ +#define HIGHEST_READ_REG (0x7D) +/* + * Total number of register count used in the initialization. + * + * note + * This should be kept exactly as the register count in the + * initialization of the platform device structure + * adux1050_platform_data. + */ +#define REGCNT (28) + +/* + * Non-Register defines + */ +/* default proxy work frequency */ +#define DEFAULT_CNT (15) +/* maximum iterations for binary search */ +#define MAX_SEARCH_DEPTH (4) +/* Total stages count */ +#define TOTAL_STG (4) +/* Total CIN Count */ +#define TOTAL_CIN (4) +/* adux1050 vendor name. */ +#define VENDOR_NAME "adi" +/* Device name */ +#define DEVICE_NAME "adux1050" +/* Driver name of this adux1050 driver */ +#define DRIVER_NAME "adux1050_generic" +/* This hold the product ID of ADUX1050 */ +#define ADUX1050_GENERIC_ID (0x5000) +/* Device/product ID mask */ +#define ADUX1050_ID_MASK (0xFF00) +/* ADUX1050 revision ID mask */ +#define REV_ID_MASK (0xF0) +/* ADUX1050 metal revision ID mask */ +#define METAL_REV_ID_MASK (0x0F) +/* Metal version 50A0/50A1 */ +#define MET_VER1 (1) +/* Extracting metal ID alone */ +#define METAL_ID(x) (x & METAL_REV_ID_MASK) +/* Extracting REV ID alone */ +#define REV_ID(x) (x & (REV_ID_MASK >> 4)) +/* Extracting metal product ID alone */ +#define PRODUCT_ID(x) (x >> 8) +/* Mask 8 LSB bits */ +#define LOW_BYTE_MASK (0x00FF) +/* Mask 4 LSB bits */ +#define LOW_NIBBLE_MASK (0x000F) +/* Low data mask for the register */ +#define ADDR_MASK (0xFFFF0000) +/* High mask for the register address */ +#define DATA_MASK (0x0000FFFF) +/* ADUX1050 Power MODE mask */ +#define PWR_MODE_MASK (0x3) +/* ADUX1050 mask for getting the number of stages */ +#define NUM_STAGE_MASK (0xC) +/* The Auto Threshold mask value */ +#define AUTO_TH_MASK (0x4) +/* Default ADUX1050 force calibration mask */ +#define FORCE_CAL_MASK (0x8000) +/* Inverted force calibration mask */ +#define ANTI_FORCE_CAL_MASK (0x7FFF) +/* Reset mask for ADUX1050 */ +#define RESET_MASK (0x0800) +/* Hexa-decimal number base value */ +#define HEX_BASE (16) +/* Decimal base value */ +#define DECIMAL_BASE (10) +/* Minus char */ +#define MINUS_CHAR '-' +/* Space char */ +#define SPACE_CHAR " " +/* Minus value */ +#define MINUS_VAL (-1) +/* Parser address field value in the cmd parsing */ +#define PARSE_ADDR (0) +/* Parser value field value in the cmd parsing */ +#define PARSE_CNT (1) +/* Parser data field start value in the cmd parsing */ +#define PARSE_DATA (2) +/* I2C transfer length for a single read/write operation */ +#define I2C_WRMSG_LEN (2) +/* I2C read/write operation buffer size max */ +#define MAX_ADUX1050_WR_LEN (24) +/* Default I2C read/write length */ +#define DEF_WR (1) +/* Count of global control registers */ +#define GLOBAL_REG_CNT (6) +/* Count of stage configuration control registers */ +#define STG_CNF_CNT (20) +/* Count of status registers */ +#define STATUS_REG_CNT (14) +/* Maximum DAC offset value */ +#define MAX_OFFSET (510) /* INSTEAD of 512 */ +/* Positive swap clear */ +#define CLR_POS_SWAP (0xBFFF) +/* Negative swap clear */ +#define CLR_NEG_SWAP (0xDFFF) +/* Positive swap set */ +#define SET_POS_SWAP (0x4000) +/* Negative swap set */ +#define SET_NEG_SWAP (0x2000) +/* Clear interrupt enable register */ +#define DISABLE_DEV_INT (0x1FF) +/* Interrupt polarity mask for ACTIVE_LOW */ +#define ACTIVE_LOW (0x0) +/* Interrupt polarity mask for ACTIVE_HIGH */ +#define ACTIVE_HIGH (0x200) +/* To get the hysteresis value from the register. */ +#define HYS_BYTE_MASK (0x00FF) +/* Initial DAC compensation codes in saturation. */ +#define DAC_CODEOUT_SAT (60000) +/* Configuration file parameters count */ +#define FILP_PARAM_CNT (5) +/* Zero's value */ +#define ZERO_VAL (0) +/* ADUX1050 full scale value */ +#define FULL_SCALE_VALUE (0xFFFF) +/* ADUX1050 zero scale value */ +#define ZERO_SCALE_VALUE (0x0000) +/* Conversion complete bit location */ +#define CONV_COMPLETE_BIT (0x100) + +/* ADUX1050 half scale value */ +#define HALF_SCALE_VAL (FULL_SCALE_VALUE / 2) +/* To get the low status */ +#define GET_LOW_STATUS(status) (((status) & 0xF0) >> 4) +/* To get the high status */ +#define GET_HIGH_STATUS(status) ((status) & 0x0F) +/* To get the Conversion complete status */ +#define GET_CONV_STATUS(status) ((status & 0x0100) >> 8) +/* Set power mode */ +#define SET_PWR_MODE(pwr, mode) (((pwr) & ~PWR_MODE_MASK) | (mode)) +/* Get power mode */ +#define GET_PWR_MODE(pwr) ((pwr) & PWR_MODE_MASK) +/* Get digital offset */ +#define GET_DIGI_OFFSET(x, y) (((x)-(y))/16) +/* Digital Offset's allowed size */ +#define DIGI_OFFSET_SIZE (2032) +/* Clamp for the digital offset */ +#define CLAMP_DIGI_OFFSET(x) (((x) > 127) ? 127 : ((-(x) > 127) ? -127 : x)) +/* Get the hysteresis register number */ +#define GET_HYS_REG(stg) (((stg) * 5) + HYS_STG0_REG) +/* Get the CONFIG_STGx register */ +#define GET_CONFIG_REG(stg) (((stg) * 5) + CONFIG_STG0_REG) +/* GET_AFE_REG to get the current stages AFE register address */ +#define GET_OFFSET_REG(stg) (((stg)*5) + OFFSET_DAC_STG0_REG) +/* To get the high threshold register value */ +#define GET_HIGH_TH_REG(stg) (((stg) * 5) + HIGH_TH_STG0_REG) +/* To get the low threshold register value */ +#define GET_LOW_TH_REG(stg) (((stg) * 5) + LOW_TH_STG0_REG) +/* To get the phase conversion time */ +#define GET_CONV_TIME(reg) (((((reg) & 0x3FC0) >> 6) > 20) ? \ + (((reg) & 0x3FC0) >> 6) : 20) +/* Check for "Is the Measure noise bit set" */ +#define IS_NOISE_MEASURE_EN(stg_cfg) ((stg_cfg) & 0x0400) +/* To get the Noise Sample count */ +#define GET_NOISE_SAMPLE(cv_time_ctrl) (1 << (((cv_time_ctrl) >> 14) + 1)) +/* Get number of measurement stages */ +#define GET_NUM_STG(pwr) ((((pwr) & NUM_STAGE_MASK) >> 2) + 1) +/* Get BASE_LINE register */ +#define GET_BASE_LINE_REG(stg) ((stg) + BASELINE_STG0_REG) +/* Get noise measurement register */ +#define GET_NOISE_MES_REG(stg) ((stg) + PK2P_STG0_REG) +/* Get result register for a stage */ +#define GET_RESULT_REG(stg) ((stg) + RESULT_STG0_REG) +/* Get AUTO_WAKE_UP time */ +#define GET_AUTO_WAKE_TIME(pwr) (((pwr) >> 12) * 20) +/* Get conversion time for ADUX1050 in TIMED CONV mode */ +#define GET_TIMED_CONV_TIME(pwr) (((((pwr) & 0x00F0) >> 4) + 1) * 100) +/* To check if the minimum time setting is done */ +#define CHECK_MIN_TIME(cv_time_ctrl) (((cv_time_ctrl) & ~(0xFFE0)) || \ + !((cv_time_ctrl) & 0x20)) +/* To check whether Conversion complete interrupt is enabled or not */ +#define CHECK_CONV_EN(int_ctrl) (!(((int_ctrl) & CONV_COMPLETE_BIT) >> 8)) +/* To check whether High threshold interrupt is enabled or not */ +#define CHECK_THRESH_HIGH_EN(int_ctrl) ((~((int_ctrl) & (0xF))) & 0xF) +/* To check whether Low threshold interrupt is enabled or not */ +#define CHECK_THRESH_LOW_EN(int_ctrl) ((~(((int_ctrl) & (0xF0)) >> 4)) & 0xF) + +/* To check whether SW Rest bit is enabled or not */ +#define CHK_SW_RESET_EN(ctrl_reg) (ctrl_reg & RESET_MASK) +/* To Clear SW Reset enable */ +#define CLR_SW_RESET_EN(ctrl_reg) (ctrl_reg & ~RESET_MASK) +/* To Set SW Reset enable */ +#define SET_SW_RESET_EN(ctrl_reg) (ctrl_reg | RESET_MASK) +/* To Check for Force Calibration enable */ +#define CHK_FORCE_CALIB_EN(bs_reg) (bs_reg & FORCE_CAL_MASK) +/* To Clear Force Calibration mask */ +#define CLR_FORCE_CALIB_EN(bs_reg) (bs_reg & ~FORCE_CAL_MASK) +/* To Force calibrate the device */ +#define SET_FORCE_CALIB_EN(bs_reg) (bs_reg | FORCE_CAL_MASK) +/* To set Minimal AVG and OSR use the following */ +#define SET_MIN_TIME(cv_time_ctrl) (((cv_time_ctrl) & 0xFFC0) | 0x20) +/* Get the DAC step size for the given cin range */ +#define GET_ARB_DAC_STEP_SIZE(cin) ((1 << (cin)) * (650)) +/* To get the AVG parameter from conv_time register */ +#define GET_AVG_CONV(conv_tmr) (((conv_tmr) & 0x3) + 1) +/* To icalculate the AVG multiplier from avg */ +#define CALC_AVG_CONV(avg) (((avg) > 1) ? (1 << (avg)) : (avg)) +/* To get the OSR parameter from the conv_time register */ +#define GET_OSR_CONV(conv_tmr) (((conv_tmr) & 0x38) >> 3) +/* To get the OSR parameter from the conv_time register */ +#define CALC_OSR_CONV(osr) (((osr) < 4) ? 1 : (1 << ((osr) - 4))) +/* Get CIN_RANGE value */ +#define GET_CIN_RANGE(ctrl_reg) (((ctrl_reg) & 0x0300) >> 8) +/* Used to set the required CIN_range of the device */ +#define SET_CIN_RANGE(pwr, cin) (((pwr) & ~(0x0300)) | ((cin) << 8)) +/* To get the DAC step size to increment for the given CDC difference & cin */ +#define GET_DAC_STEP_SIZE(x, cin) ((u32)(x) / ((1 << (cin)) * 650)) +/* To get the POS AFE value */ +#define LD_POS_DAC_OFFSET(x, y) ((((x) & 0xFF00) >> 8) * \ + (((y) & 0x4000) ? -1 : 1)) +/* Macro to get the NEG AFE value */ +#define LD_NEG_DAC_OFFSET(x, y) (((x) & 0x00FF) * (((y) & 0x2000) ? 1 : -1)) +/* Macro to set the POS AFE value */ +#define ST_POS_DAC_OFFSET(x) ((x > 255) ? ((x - 255) << 8) | 0x00FF : x << 8) +/* Macro to set the NEG AFE value */ +#define ST_NEG_DAC_OFFSET(x) ((-x > 255) ? (-x - 255) | 0xFF00 : (-x)) +/* To get the 60 percent of a value. */ +#define GET_60_PERCENT(x) (((x)*3)/5) +/* To check the calibration bit statua */ +#define CHECK_CAL_STATE(x, y) ((x) & (1 << (y))) +/* To clear the calibration status bit */ +#define CLR_CAL_STATUS(x, y) ((x) = (x) & ~(1 << (y))) +/* DAC calibration routine maximum loop count */ +#define CALIB_LOOP_CNT (10) +/* I2c retry count for the i2c transfer */ +#define I2C_RETRY_CNT (3) +/* Maximum DAC calibration target */ +#define MAX_CALIB_TARGET (63000) +/* Minimum DAC calibration target */ +#define MIN_CALIB_TARGET (2000) +/* Force calibration delay */ +#define FORCE_CALIB_SLEEP_TIME (300) + + +#ifdef CONFIG_ADUX1050_POLL + +/* Minimum msleep time */ +#define MSLEEP_MIN_TIME (20) +/* Min Polling time */ +#define MIN_POLL_DELAY (10) +/* Milli sec to micro second conversion factor */ +#define MS_TO_US (1000) + +#endif + +#define TRUE (1) +#define FALSE (0) +/**to convert proxy time units to seconds*/ +#define PROXY_TIME (1000) + + +/* Event packing for STATUS */ +#define PACK_FOR_STATUS_EVENT(status, prox_status) ((status << HEX_BASE) |\ + (prox_status << 4) |\ + (CONV_COMP_STATUS)) +/* Event packing for BASELINE */ +#define PACK_FOR_BASELINE_EVENT(baseline, stage_num) ((baseline << HEX_BASE) |\ + (stage_num << 4) |\ + (CONV_COMP_BASELINE)) +/* Event packing for CDC Interrupt */ +#define PACK_FOR_CDC_EVENT(cdc_value, stage_num) ((cdc_value << HEX_BASE) |\ + (stage_num << 4) |\ + (CONV_COMPLETE)) +/* Event packing for Active event */ +#define PACK_FOR_ACTIVE_STATE(stg_num, th_type) ((TH_ACTIVE << 12) |\ + (th_type << 8) |\ + (stg_num << 4) |\ + (THRESHOLD_CROSS)) +/* Event packing for Idle event */ +#define PACK_FOR_IDLE_STATE(stg_num, th_type) ((TH_IDLE << 12) |\ + (th_type << 8) |\ + (stg_num << 4) |\ + (THRESHOLD_CROSS)) + +/* Driver state */ +enum device_state { + ADUX1050_DISABLE = 0, + ADUX1050_ENABLE, + ADUX1050_SUSPEND +}; + +/* DAC Calibration return status */ +enum calib_ret_status { + CAL_RET_NONE = 0, + CAL_RET_EXIST, + CAL_RET_SUCCESS, + CAL_RET_FAIL, + CAL_RET_PENDING +}; +/* Interrupt types of ADUX1050 */ +enum interrupt_types { + CONV_COMPLETE = 0, + THRESHOLD_CROSS, + CONV_COMP_BASELINE, + CONV_COMP_STATUS +}; +/* Threshold types */ +enum threshold_types { + TH_LOW = 0, + TH_HIGH +}; +/* Threshold states */ +enum threshold_states { + TH_IDLE = 0, + TH_ACTIVE +}; +/* Allowed power modes */ +enum power_mode { + PWR_STAND_BY = 0, + PWR_FULL_POWER, + PWR_TIMED_CONV, + PWR_AUTO_WAKE +}; +/* Allowed stage numbers */ +enum stage_no { + STG_ZERO = 0, + STG_ONE, + STG_TWO, + STG_THREE +}; +/* Allowed Cin Range */ +enum cin_range { + PICO_5 = 0, + PICO_2P5, + PICO_1P25, + PICO_0P625 +}; +/* CIN Connection status */ +enum cin_con { + CIN_NOT_CONNECTED = 0, + CIN_CONNECTED +}; +/* CIN Connection setup */ +enum cin_conn_setup { + CIN_GND = 0, + CIN_NEG_INPUT, + CIN_POS_INPUT, + CIN_SHIELD +}; +/* enum for the conversion time calculation */ +enum conv_calc_factor { + TWICE_CONV_DELAY_TIME, + CONV_TIME, + CONV_DELAY_TIME +}; +/* READ function prototype for ADUX1050 */ +typedef int32_t (*adux1050_read_t)(struct device *, uint8_t, uint16_t*, + uint16_t); +/* WRITE function prototype for ADUX1050 */ +typedef int32_t (*adux1050_write_t)(struct device *, uint8_t, uint16_t*, + uint16_t); + +/* + * Structure to hold register values from Device tree / Run time modifications + */ +struct adux1050_registers { + bool wr_flag; + u16 value; +}; + +/* + * Platform data structure of ADUX1050_SLD driver + */ +struct adux1050_platform_data { + /* This hold the initial register configurations of ADUX1050. */ + unsigned int init_regs[REGCNT]; + /* This holds the calbirated Factory baseline. */ + unsigned short cal_fact_base[TOTAL_STG]; + /* This holds the calibrated DAC offset. */ + unsigned short cal_offset[TOTAL_STG]; + /* This holds the digital offset for the calibrated stage. */ + unsigned short digi_offset[TOTAL_STG]; + /* This holds the required factory baseline. */ + unsigned short stg_cfg[TOTAL_STG]; + /* This holds the required stage 0 baseline. */ + unsigned short req_stg0_base; + /* This holds the required stage 1 baseline. */ + unsigned short req_stg1_base; + /* This holds the required stage 2 baseline. */ + unsigned short req_stg2_base; + /* This holds the required stage 3 baseline. */ + unsigned short req_stg3_base; + /* This holds the irq flags for the device. */ + unsigned short irq_flags; + /* This holds the irq gpio number for the device. */ + bool is_set_irq_gpio_no; + unsigned short irq_gpio_no; + /* This holds the force calib variables for the device. */ + bool proxy_enable; + unsigned short allowed_proxy_time; + unsigned short max_proxy_count; + /* This holds user error threshold bits for each stage. */ + unsigned intr_err; +}; + +struct adux1050_stage_info { + enum cin_con status; + unsigned char index; +}; +struct dac_calib_structure { + /* Interrupt enable setting */ + u16 enable_setting; + /* Overall DAC calibration status */ + u8 cal_flags; + /* + * Used to denote to do or clear the DAC calibration + * for the next calibration call + */ + u8 action_flag; + /* calibration status for each stage */ + u8 stg_cal_stat; + /* Saturation complete status */ + u8 sat_comp_stat; +}; +/* + * This is the chip structure which contains software structures and + * other essential for the operation of the device. + */ +struct adux1050_chip { + /* This holds the registers value */ + struct adux1050_registers reg[GLOBAL_REG_CNT + STG_CNF_CNT]; + /* This holds the baseline registers value */ + struct adux1050_registers bs_reg[TOTAL_STG]; + /* Platform data pointer */ + struct adux1050_platform_data *pdata; + /* Stages information */ + struct adux1050_stage_info *stg_info; + /* Registered input device pointer */ + struct input_dev *input; + /* Registered workstructure for the IRQ */ + struct work_struct work; + /* Registered workstructure for the DAC calibration work */ + struct work_struct calib_work; + /* Registered delayed work for force calibration on proximity */ + struct delayed_work proxy_work; + /* I2C client device pointer */ + struct device *dev; + /* Chip mutex */ + struct mutex mutex; /* Chip Mutex */ + /* Device calibration status structure */ + struct dac_calib_structure dac_calib; +#ifdef CONFIG_OF + /* DT node pointer */ + struct device_node *dt_device_node; +#endif +#ifdef CONFIG_ADUX1050_POLL + /* Kernel Polling Task struct for the adux1050. */ + struct task_struct *polling_task; +#endif + /* Read op pointer */ + adux1050_read_t read; + /* Write op pointer */ + adux1050_write_t write; + /* IRQ number */ + s32 irq; + /* to set/reset or increament the count on constant proximity */ + u32 proxy_count; + /* to store the proximity time limit to do force_calib */ + u32 allowed_proxy_time; + /* to store the max count value to do force calib */ + u32 max_proxy_count; +#ifdef CONFIG_ADUX1050_EVAL + /* Reg buffer for read registers */ + u16 stored_reg_data[MAX_ADUX1050_WR_LEN]; + /* Stored registers count in Reg buffer */ + u16 stored_data_cnt; +#endif +#ifdef CONFIG_ADUX1050_POLL + /* Kernel Polling task delay time */ + u16 poll_delay; +#endif + + /* + * Device enable to enable the adux1050 chip + * 0 - Disabled + * 1 - Enabled + * 2 - Suspended + */ + u16 dev_enable; + /* sleep time required for the current conversion settings */ + u16 slp_time_conv_complete; + /* Stage connected count */ + u16 conn_stg_cnt; + /* Current power mode */ + u16 ctrl_reg; + /* Interrupt Control */ + u16 int_ctrl; + /* Prev current high status */ + u16 prev_high_status; + /* Prev current low status */ + u16 prev_low_status; + /* Current high status */ + u16 high_status; + /* Current low status */ + u16 low_status; + /* Conversion complete status */ + u16 conv_status; + /* Current interrupt status */ + u16 int_status; + /* Used to store the initial dac offset value */ + u16 cur_dac_offset[TOTAL_STG]; + /* Used to store the initial swap state */ + u16 cur_swap_state[TOTAL_STG]; + /* This hold the number of stage */ + u16 tot_stg; + /* Used to store the interrupt polarity */ + u16 int_pol; + /* Product ID of the device */ + u16 product; + /* Used to store version ID */ + u16 version; + /* Chip metal version */ + u16 metal_id; + /* Send event to enable/disable the input event */ + s8 send_event; + /* Error bits to do foce calib */ + u8 user_intr_err; + /* used to enable the Force_calib on proximity */ + u8 proxy_enable; + /* Low threshold interrupt control */ + u8 low_thresh_enable; + /* High threshold interrupt control */ + u8 high_thresh_enable; + /* Number of measurement stages */ + u8 num_stages; + /* Stage number to read raw CDC */ + u8 stg_raw_cdc; + /* Stage number to show threshold details */ + u8 stg_threshold; + /* Conversion enable */ + bool conv_enable; + bool proxy_cancel; + /* Power mode setting flag */ + bool power_mode_flag; +}; + +#endif /* __LINUX_INPUT_ADUX1050_H__ */ diff --git a/include/linux/input/bu520x1nvx.h b/include/linux/input/bu520x1nvx.h new file mode 100644 index 0000000000000000000000000000000000000000..f1ff0642b21e421253cf0f07c0ac32792cd561d8 --- /dev/null +++ b/include/linux/input/bu520x1nvx.h @@ -0,0 +1,39 @@ +/* include/linux/input/bu520x1nvx.h + * + * Author: Atsushi Iyogi + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef _LINUX_INPUT_BU520X1NVX_H +#define _LINUX_INPUT_BU520X1NVX_H + +struct device; + +struct bu520x1nvx_gpio_event { + bool lid_pin; + int gpio; + int active_low; + const char *desc; + int debounce_interval; + int open_debounce_interval; + int close_debounce_interval; + unsigned int irq; +}; + +struct bu520x1nvx_platform_data { + int n_events; + struct bu520x1nvx_gpio_event *events; +}; + +#endif diff --git a/include/linux/input/evdt_helper.h b/include/linux/input/evdt_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..91e67739e928e1056efbef109c5321e4ed87ab70 --- /dev/null +++ b/include/linux/input/evdt_helper.h @@ -0,0 +1,175 @@ +/* include/linux/input/evdt_helper.h + * + * Author: Kenji Suzuki + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_INPUT_EVDT_HELPER_H__ +#define __LINUX_INPUT_EVDT_HELPER_H__ + +#include +#include +#include + +enum { + EVDT_MSLEEP = 0, + EVDT_KEY, + EVDT_LOG, + EVDT_END = 99, +}; + +static inline int evdt_get_msleep(struct device_node *node, u32 *ms) +{ + return of_property_read_u32(node, "ms", ms); +} + +static inline int evdt_get_key(struct device_node *node, u32 *code, u32 *down) +{ + int rc; + rc = of_property_read_u32(node, "code", code); + if (!rc) + rc = of_property_read_u32(node, "down", down); + return rc; +} + +static inline int evdt_get_log(struct device_node *node, const char **message) +{ + return of_property_read_string(node, "message", message); +} + +static inline struct device_node *evdt_initialize(struct device *dev, + struct input_dev *input, const char *node) +{ + struct device_node *wg_node = NULL; + struct device_node *block = NULL; + struct device_node *record = NULL; + int index = 0; + u32 type; + u32 ms; + u32 code; + u32 down; + const char *message; + int rc; + + if (!dev->of_node || !input) + return NULL; + + wg_node = of_find_node_by_name(dev->of_node, node); + if (!wg_node) { + pr_err("%s: No %s node found\n", __func__, node); + return NULL; + } + + for_each_child_of_node(wg_node, block) { + index = 0; + for_each_child_of_node(block, record) { + rc = of_property_read_u32(record, "type", &type); + if (rc) + goto error; + + switch (type) { + case EVDT_MSLEEP: + rc = evdt_get_msleep(record, &ms); + if (rc) + goto error; + pr_info("%s: MSLEEP [%u]\n", __func__, ms); + break; + case EVDT_KEY: + rc = evdt_get_key(record, &code, &down); + if (rc) + goto error; + input_set_capability(input, EV_KEY, code); + pr_info("%s: KEY [%u, %s]\n", __func__, code, + down ? "DOWN" : "UP"); + break; + case EVDT_LOG: + rc = evdt_get_log(record, &message); + if (rc) + goto error; + pr_info("%s: LOG [%s]\n", __func__, message); + break; + case EVDT_END: + default: + break; + } + index++; + } + } + return wg_node; + +error: + pr_err("%s: invalid value at index %d for %s rc=%d\n", + __func__, index, block->name, rc); + return NULL; +} + +static inline int evdt_execute(struct device_node *block, + struct input_dev *input, u16 gesture_code) +{ + struct device_node *gesture = NULL; + struct device_node *record; + u32 type; + u32 ms; + u32 code; + u32 down; + const char *message; + int rc; + + if (!block || !input) + return 0; + + for_each_child_of_node(block, gesture) { + rc = of_property_read_u32(gesture, "gesture_code", &type); + if (rc) { + pr_err("%s: Error reading gesture_code for %s rc=%d\n", + __func__, gesture->name, rc); + return rc; + } + + if (gesture_code != type) + continue; + + for_each_child_of_node(gesture, record) { + of_property_read_u32(record, "type", &type); + + switch (type) { + case EVDT_MSLEEP: + evdt_get_msleep(record, &ms); + pr_debug("%s: MSLEEP(%d)\n", __func__, ms); + msleep(ms); + break; + case EVDT_KEY: + evdt_get_key(record, &code, &down); + pr_debug("%s: KEY(%d) %s\n", __func__, code, + down ? "DOWN" : "UP"); + input_report_key(input, code, down); + input_sync(input); + break; + case EVDT_LOG: + evdt_get_log(record, &message); + pr_info("%s: %s\n", __func__, message); + break; + case EVDT_END: + default: + goto loop_end; + } + } + } + pr_warn("%s: Gesture code 0x%X not defined\n", __func__, gesture_code); + +loop_end: + return 0; +} + +#endif /* __LINUX_INPUT_EVDT_HELPER_H__ */ diff --git a/include/linux/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h index a2624ab57826899bf7e4c64d25e342aa5a4021b9..2cd9316e5362f1bace9e24ec2bfba7133b8b7043 100644 --- a/include/linux/input/qpnp-power-on.h +++ b/include/linux/input/qpnp-power-on.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef QPNP_PON_H #define QPNP_PON_H @@ -51,13 +56,21 @@ enum pon_power_off_type { }; enum pon_restart_reason { - PON_RESTART_REASON_UNKNOWN = 0x00, - PON_RESTART_REASON_RECOVERY = 0x01, - PON_RESTART_REASON_BOOTLOADER = 0x02, - PON_RESTART_REASON_RTC = 0x03, - PON_RESTART_REASON_DMVERITY_CORRUPTED = 0x04, - PON_RESTART_REASON_DMVERITY_ENFORCE = 0x05, - PON_RESTART_REASON_KEYS_CLEAR = 0x06, + PON_RESTART_REASON_NONE = 0x00, + PON_RESTART_REASON_UNKNOWN = 0x01, + PON_RESTART_REASON_RECOVERY = 0x02, + PON_RESTART_REASON_BOOTLOADER = 0x03, + PON_RESTART_REASON_RTC = 0x04, + PON_RESTART_REASON_DMVERITY_CORRUPTED = 0x05, + PON_RESTART_REASON_DMVERITY_ENFORCE = 0x06, + PON_RESTART_REASON_KEYS_CLEAR = 0x07, + PON_RESTART_REASON_KERNEL_PANIC = 0x40, + PON_RESTART_REASON_UNHANDLED_RESET = 0x41, + PON_RESTART_REASON_FOTA_CRASH = 0x42, + PON_RESTART_REASON_OEM_F = 0x50, + PON_RESTART_REASON_OEM_P = 0x51, + PON_RESTART_REASON_XFL = 0x60, + PON_RESTART_REASON_SYSTEM = 0x61, }; #ifdef CONFIG_INPUT_QPNP_POWER_ON diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index b3b1af8a8f8c1189676e47ae43c30b646ed7e34d..14335856f70809d80ca40cf105abd6e106f8570e 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -1,4 +1,9 @@ /* interrupt.h */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _LINUX_INTERRUPT_H #define _LINUX_INTERRUPT_H @@ -62,6 +67,9 @@ * wakeup devices users need to implement wakeup detection in * their interrupt handlers. */ +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +#define IRQF_DISABLED 0x00000020 +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ #define IRQF_SHARED 0x00000080 #define IRQF_PROBE_SHARED 0x00000100 #define __IRQF_TIMER 0x00000200 diff --git a/include/linux/ipa.h b/include/linux/ipa.h index a4b817c5e4fc3dc2b3e160b9b43ae05f0104aa37..c11a5c4afece81a843fe3d71ac54874a31c8c43c 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -39,14 +39,6 @@ enum ipa_nat_en_type { IPA_DST_NAT, }; -/** - * enum ipa_ipv6ct_en_type - IPv6CT setting type in IPA end-point - */ -enum ipa_ipv6ct_en_type { - IPA_BYPASS_IPV6CT, - IPA_ENABLE_IPV6CT, -}; - /** * enum ipa_mode_type - mode setting type in IPA end-point * @BASIC: basic mode @@ -126,19 +118,6 @@ struct ipa_ep_cfg_nat { enum ipa_nat_en_type nat_en; }; -/** - * struct ipa_ep_cfg_conn_track - IPv6 Connection tracking configuration in - * IPA end-point - * @conn_track_en: Defines speculative conn_track action, means if specific - * pipe needs to have UL/DL IPv6 Connection Tracking or Bypass - * IPv6 Connection Tracking. 0: Bypass IPv6 Connection Tracking - * 1: IPv6 UL/DL Connection Tracking. - * Valid for Input Pipes only (IPA consumer) - */ -struct ipa_ep_cfg_conn_track { - enum ipa_ipv6ct_en_type conn_track_en; -}; - /** * struct ipa_ep_cfg_hdr - header configuration in IPA end-point * @@ -407,8 +386,7 @@ struct ipa_ep_cfg_seq { /** * struct ipa_ep_cfg - configuration of IPA end-point - * @nat: NAT parameters - * @conn_track: IPv6CT parameters + * @nat: NAT parmeters * @hdr: Header parameters * @hdr_ext: Extended header parameters * @mode: Mode parameters @@ -422,7 +400,6 @@ struct ipa_ep_cfg_seq { */ struct ipa_ep_cfg { struct ipa_ep_cfg_nat nat; - struct ipa_ep_cfg_conn_track conn_track; struct ipa_ep_cfg_hdr hdr; struct ipa_ep_cfg_hdr_ext hdr_ext; struct ipa_ep_cfg_mode mode; diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 50220cab738c1d816f7f4117c2ae19baeb2561da..384e7005cf2c90b5cf01bc2530e713aeeaf5b549 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _LINUX_KERNEL_H #define _LINUX_KERNEL_H @@ -558,6 +563,7 @@ void tracing_snapshot_alloc(void); extern void tracing_start(void); extern void tracing_stop(void); +#ifdef CONFIG_TRACE_PRINTK static inline __printf(1, 2) void ____trace_printk_check_format(const char *fmt, ...) { @@ -627,6 +633,20 @@ int __trace_bprintk(unsigned long ip, const char *fmt, ...); extern __printf(2, 3) int __trace_printk(unsigned long ip, const char *fmt, ...); +#else +static inline __printf(1, 2) +int trace_printk(const char *fmt, ...) +{ + return 0; +} + +static inline int +ftrace_vprintk(const char *fmt, va_list ap) +{ + return 0; +} +#endif /* CONFIG_TRACE_PRINTK */ + /** * trace_puts - write a string into the ftrace buffer * @str: the string to record diff --git a/include/linux/ldo_vibrator.h b/include/linux/ldo_vibrator.h new file mode 100644 index 0000000000000000000000000000000000000000..03e53fc846080dc0045e05009447a80cebf86414 --- /dev/null +++ b/include/linux/ldo_vibrator.h @@ -0,0 +1,41 @@ +/* + * Authors: Atsushi Iyogi + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef _LINUX_LDO_VIBRATOR_H +#define _LINUX_LDO_VIBRATOR_H + +#include +#include +#include +#include +#include +#include +#include <../../drivers/staging/android/timed_output.h> + +#define LDO_VIBRATOR_NAME "ldo_vibrator" + +struct ldo_vibrator_data { + struct device *dev; + struct hrtimer vib_timer; + struct timed_output_dev timed_dev; + struct work_struct work; + + int gpio; + int state; + int timeout; + struct mutex lock; +}; +#endif diff --git a/include/linux/leds.h b/include/linux/leds.h index 197b61500ab768f53be9a0d8c5213046ff6e6c55..ff772726736799cb7baf907c22f8af7605b33aa3 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -9,6 +9,11 @@ * published by the Free Software Foundation. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __LINUX_LEDS_H_INCLUDED #define __LINUX_LEDS_H_INCLUDED diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h index 743b34f56f2be813371a4c55f1e8c36578bd3d2f..2a6b9947aaa3191e7f24708dcd8726ccb2418b9f 100644 --- a/include/linux/list_lru.h +++ b/include/linux/list_lru.h @@ -44,7 +44,6 @@ struct list_lru_node { /* for cgroup aware lrus points to per cgroup lists, otherwise NULL */ struct list_lru_memcg *memcg_lrus; #endif - long nr_items; } ____cacheline_aligned_in_smp; struct list_lru { diff --git a/include/linux/mfd/qcom_rpm.h b/include/linux/mfd/qcom_rpm.h index 742ebf1b76ca2e74a14bb3b48eeab92653948d48..a9b9b977ccb694cda6fa07ecef1da1ed44eb0f5d 100644 --- a/include/linux/mfd/qcom_rpm.h +++ b/include/linux/mfd/qcom_rpm.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ #ifndef __QCOM_RPM_H__ #define __QCOM_RPM_H__ diff --git a/include/linux/migrate.h b/include/linux/migrate.h index ae8d475a9385226a7af27a39d40a10937b0721e0..5219df44cfec511ce8c45586348ba5465959949f 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -23,13 +23,9 @@ enum migrate_reason { MR_SYSCALL, /* also applies to cpusets */ MR_MEMPOLICY_MBIND, MR_NUMA_MISPLACED, - MR_CMA, - MR_TYPES + MR_CMA }; -/* In mm/debug.c; also keep sync with include/trace/events/migrate.h */ -extern char *migrate_reason_names[MR_TYPES]; - #ifdef CONFIG_MIGRATION extern void putback_movable_pages(struct list_head *l); diff --git a/include/linux/mm.h b/include/linux/mm.h index 7d0b5e7bcadb26d884d7fafab62ddf113a5c95ec..509fc6a36cbae3f15416dca483ce9998677c909f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _LINUX_MM_H #define _LINUX_MM_H @@ -529,6 +534,7 @@ void put_page(struct page *page); void put_pages_list(struct list_head *pages); void split_page(struct page *page, unsigned int order); +int split_free_page(struct page *page); /* * Compound pages have a destructor function. Provide a diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 8e76f46adde3df7fa69fff841a9ab60de36020c8..c192913b0c3cdc1b22cc4b43eac855a6429be06d 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -7,6 +7,11 @@ * * Card driver specific definitions. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef LINUX_MMC_CARD_H #define LINUX_MMC_CARD_H @@ -238,6 +243,7 @@ enum mmc_blk_status { MMC_BLK_ECC_ERR, MMC_BLK_NOMEDIUM, MMC_BLK_NEW_REQUEST, + MMC_BLK_RETRY_SINGLE, }; enum mmc_packed_stop_reasons { @@ -342,6 +348,25 @@ enum mmc_pon_type { #define MMC_QUIRK_CMDQ_DELAY_BEFORE_DCMD 6 /* microseconds */ +#ifdef CONFIG_MMC_CMD_DEBUG +#define CMD_QUEUE_SIZE CONFIG_MMC_CMD_QUEUE_SIZE +#endif + +#ifdef CONFIG_MMC_CMD_DEBUG +struct mmc_cmdq { + u32 opcode; + u32 arg; + u32 flags; + u64 timestamp; +}; + +struct mmc_cmd_stats { + u32 next_idx; + u32 wrapped; + struct mmc_cmdq cmdq[CMD_QUEUE_SIZE]; +}; +#endif + /* * MMC device */ @@ -436,6 +461,9 @@ struct mmc_card { struct notifier_block reboot_notify; enum mmc_pon_type pon_type; bool cmdq_init; +#ifdef CONFIG_MMC_CMD_DEBUG + struct mmc_cmd_stats cmd_stats; +#endif struct mmc_bkops_info bkops; bool err_in_sdr104; bool sdr104_blocked; diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 08b3b8348fd7d125c88cd9556cfc31cbac0425c0..0065ffc9322bf281faaf1166cb8307db545b7cb8 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -170,7 +170,6 @@ extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); extern int mmc_set_auto_bkops(struct mmc_card *card, bool enable); extern int mmc_suspend_clk_scaling(struct mmc_host *host); -extern void mmc_flush_detect_work(struct mmc_host *); #define MMC_ERASE_ARG 0x00000000 #define MMC_SECURE_ERASE_ARG 0x80000000 diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 65a188eeeeb64e3c2445c11a4304648a52d701b7..9134b3c87d9edde6d42175bbae3d04912328ca79 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -7,6 +7,11 @@ * * Host driver specific definitions. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef LINUX_MMC_HOST_H #define LINUX_MMC_HOST_H @@ -24,7 +29,10 @@ #include #include +/* Default idle timeout for MMC devices: 3 seconds. */ #define MMC_AUTOSUSPEND_DELAY_MS 3000 +/* Default idle timeout for SD cards: 5 minutes. */ +#define MMC_SDCARD_AUTOSUSPEND_DELAY_MS 30000 struct mmc_ios { unsigned int clock; /* clock rate */ @@ -519,7 +527,6 @@ struct mmc_host { unsigned int bus_resume_flags; #define MMC_BUSRESUME_MANUAL_RESUME (1 << 0) #define MMC_BUSRESUME_NEEDS_RESUME (1 << 1) - bool ignore_bus_resume_flags; unsigned int sdio_irqs; struct task_struct *sdio_irq_thread; diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h index 3945a8c9d3cbf68ba386b60166ec0b9b359e50d0..dbc9ccb587c0f4ad4592905ed22291d446aa5fc7 100644 --- a/include/linux/mmc/slot-gpio.h +++ b/include/linux/mmc/slot-gpio.h @@ -7,6 +7,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef MMC_SLOT_GPIO_H #define MMC_SLOT_GPIO_H @@ -30,4 +35,10 @@ void mmc_gpio_set_cd_isr(struct mmc_host *host, irqreturn_t (*isr)(int irq, void *dev_id)); void mmc_gpiod_request_cd_irq(struct mmc_host *host); +void mmc_gpio_init_uim2(struct mmc_host *host, unsigned int gpio); +void mmc_gpio_set_uim2_en(struct mmc_host *host, int value); +void mmc_gpio_tray_close_set_uim2(struct mmc_host *host, int value); +#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME +void mmc_cd_prepare_suspend(struct mmc_host *host); +#endif #endif diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 2b1be7efde55baa3d441e435d50b48d36510eafe..9d1161a8d6b74f7a3477077052a5eb9ae67c7f83 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -71,9 +71,6 @@ enum { */ extern int *get_migratetype_fallbacks(int mtype); -/* In mm/page_alloc.c; keep in sync also with show_migration_types() there */ -extern char * const migratetype_names[MIGRATE_TYPES]; - #ifdef CONFIG_CMA bool is_cma_pageblock(struct page *page); # define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA) diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index f5349823d0d295aa40a75a817c89543a01473bfd..a846de1af12a3408e2c14ef091b189a5e110840a 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -291,7 +291,7 @@ struct pcmcia_device_id { #define INPUT_DEVICE_ID_LED_MAX 0x0f #define INPUT_DEVICE_ID_SND_MAX 0x07 #define INPUT_DEVICE_ID_FF_MAX 0x7f -#define INPUT_DEVICE_ID_SW_MAX 0x20 +#define INPUT_DEVICE_ID_SW_MAX 0x1f #define INPUT_DEVICE_ID_MATCH_BUS 1 #define INPUT_DEVICE_ID_MATCH_VENDOR 2 diff --git a/include/linux/msm_audio_ion.h b/include/linux/msm_audio_ion.h index 9e77ac317c282f084b0f49c79b5043813d80fcc8..0761b880ca88cc38632a87d7f802641cab415291 100644 --- a/include/linux/msm_audio_ion.h +++ b/include/linux/msm_audio_ion.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,12 +17,6 @@ #include #include -enum { - HLOS_TO_ADSP = 1, - ADSP_TO_HLOS, -}; - -#define VMID_CP_ADSP_SHARED 33 int msm_audio_ion_alloc(const char *name, struct ion_client **client, struct ion_handle **handle, size_t bufsz, @@ -32,7 +26,6 @@ int msm_audio_ion_import(const char *name, struct ion_client **client, struct ion_handle **handle, int fd, unsigned long *ionflag, size_t bufsz, ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr); - int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle); int msm_audio_ion_mmap(struct audio_buffer *substream, struct vm_area_struct *vma); @@ -49,13 +42,4 @@ int msm_audio_ion_import_legacy(const char *name, struct ion_client *client, int msm_audio_ion_free_legacy(struct ion_client *client, struct ion_handle *handle); u32 msm_audio_populate_upper_32_bits(ion_phys_addr_t pa); - -int msm_audio_ion_phys_assign(const char *name, struct ion_client **client, - struct ion_handle **handle, - int fd, ion_phys_addr_t *paddr, - size_t *pa_len, u8 assign_type); -int msm_audio_ion_phys_free(struct ion_client *client, - struct ion_handle *handle, - ion_phys_addr_t *paddr, - size_t *pa_len, u8 assign_type); #endif /* _LINUX_MSM_AUDIO_ION_H */ diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h index 03f2a3e7d76d40ee457b8ab6f2d140d1ee9475b1..17f118a82854960701dac4de69dfc1af43713989 100644 --- a/include/linux/page_ext.h +++ b/include/linux/page_ext.h @@ -3,7 +3,6 @@ #include #include -#include struct pglist_data; struct page_ext_operations { @@ -45,8 +44,8 @@ struct page_ext { #ifdef CONFIG_PAGE_OWNER unsigned int order; gfp_t gfp_mask; - int last_migrate_reason; - depot_stack_handle_t handle; + unsigned int nr_entries; + unsigned long trace_entries[8]; #endif }; diff --git a/include/linux/page_idle.h b/include/linux/page_idle.h index fec40271339f8044aa1e3f1743e62017f146f9cc..bf268fa92c5b34a1bffce97a8cd38acf2b161059 100644 --- a/include/linux/page_idle.h +++ b/include/linux/page_idle.h @@ -46,62 +46,33 @@ extern struct page_ext_operations page_idle_ops; static inline bool page_is_young(struct page *page) { - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return false; - - return test_bit(PAGE_EXT_YOUNG, &page_ext->flags); + return test_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags); } static inline void set_page_young(struct page *page) { - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return; - - set_bit(PAGE_EXT_YOUNG, &page_ext->flags); + set_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags); } static inline bool test_and_clear_page_young(struct page *page) { - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return false; - - return test_and_clear_bit(PAGE_EXT_YOUNG, &page_ext->flags); + return test_and_clear_bit(PAGE_EXT_YOUNG, + &lookup_page_ext(page)->flags); } static inline bool page_is_idle(struct page *page) { - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return false; - - return test_bit(PAGE_EXT_IDLE, &page_ext->flags); + return test_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags); } static inline void set_page_idle(struct page *page) { - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return; - - set_bit(PAGE_EXT_IDLE, &page_ext->flags); + set_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags); } static inline void clear_page_idle(struct page *page) { - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return; - - clear_bit(PAGE_EXT_IDLE, &page_ext->flags); + clear_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags); } #endif /* CONFIG_64BIT */ diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h index 30583ab0ffb1f8da50d6a3a5cd8e0277af78a304..cacaabea8a0950115138c956737c2bd9d7c04a90 100644 --- a/include/linux/page_owner.h +++ b/include/linux/page_owner.h @@ -1,52 +1,38 @@ #ifndef __LINUX_PAGE_OWNER_H #define __LINUX_PAGE_OWNER_H -#include - #ifdef CONFIG_PAGE_OWNER -extern struct static_key_false page_owner_inited; +extern bool page_owner_inited; extern struct page_ext_operations page_owner_ops; extern void __reset_page_owner(struct page *page, unsigned int order); extern void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask); -extern void __split_page_owner(struct page *page, unsigned int order); -extern void __copy_page_owner(struct page *oldpage, struct page *newpage); -extern void __set_page_owner_migrate_reason(struct page *page, int reason); -extern void __dump_page_owner(struct page *page); +extern gfp_t __get_page_owner_gfp(struct page *page); static inline void reset_page_owner(struct page *page, unsigned int order) { - if (static_branch_unlikely(&page_owner_inited)) - __reset_page_owner(page, order); + if (likely(!page_owner_inited)) + return; + + __reset_page_owner(page, order); } static inline void set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask) { - if (static_branch_unlikely(&page_owner_inited)) - __set_page_owner(page, order, gfp_mask); -} + if (likely(!page_owner_inited)) + return; -static inline void split_page_owner(struct page *page, unsigned int order) -{ - if (static_branch_unlikely(&page_owner_inited)) - __split_page_owner(page, order); + __set_page_owner(page, order, gfp_mask); } -static inline void copy_page_owner(struct page *oldpage, struct page *newpage) -{ - if (static_branch_unlikely(&page_owner_inited)) - __copy_page_owner(oldpage, newpage); -} -static inline void set_page_owner_migrate_reason(struct page *page, int reason) -{ - if (static_branch_unlikely(&page_owner_inited)) - __set_page_owner_migrate_reason(page, reason); -} -static inline void dump_page_owner(struct page *page) + +static inline gfp_t get_page_owner_gfp(struct page *page) { - if (static_branch_unlikely(&page_owner_inited)) - __dump_page_owner(page); + if (likely(!page_owner_inited)) + return 0; + + return __get_page_owner_gfp(page); } #else static inline void reset_page_owner(struct page *page, unsigned int order) @@ -56,18 +42,10 @@ static inline void set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask) { } -static inline void split_page_owner(struct page *page, - unsigned int order) -{ -} -static inline void copy_page_owner(struct page *oldpage, struct page *newpage) -{ -} -static inline void set_page_owner_migrate_reason(struct page *page, int reason) -{ -} -static inline void dump_page_owner(struct page *page) +static inline gfp_t get_page_owner_gfp(struct page *page) { + return 0; } + #endif /* CONFIG_PAGE_OWNER */ #endif /* __LINUX_PAGE_OWNER_H */ diff --git a/include/linux/pm.h b/include/linux/pm.h index 6a5d654f444726abc824d9d07377ad66e86c6a44..faf1e391e581eeaf4682f41fb0dc03106d876ba7 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -17,6 +17,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _LINUX_PM_H #define _LINUX_PM_H @@ -703,6 +708,11 @@ extern int dpm_suspend_late(pm_message_t state); extern int dpm_suspend(pm_message_t state); extern int dpm_prepare(pm_message_t state); +#ifdef CONFIG_PM_WAKEUP_TIMES +extern void dpm_log_start_time(pm_message_t state); +extern void dpm_log_wakeup_stats(pm_message_t state); +#endif + extern void __suspend_report_result(const char *function, void *fn, int ret); #define suspend_report_result(fn, ret) \ diff --git a/include/linux/pmic-voter.h b/include/linux/pmic-voter.h index f202bf7040559681962ba94e7c47c074f3bb0cab..2d636f458f8c73b0b354f881fd4e3effa827da58 100644 --- a/include/linux/pmic-voter.h +++ b/include/linux/pmic-voter.h @@ -15,6 +15,9 @@ #include +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +#define NUM_MAX_CLIENTS 20 +#endif struct votable; enum votable_type { @@ -46,5 +49,9 @@ struct votable *create_votable(const char *name, void destroy_votable(struct votable *votable); void lock_votable(struct votable *votable); void unlock_votable(struct votable *votable); - +#if defined(CONFIG_SOMC_CHARGER_EXTENSION) +ssize_t somc_output_voter_param(struct votable *votable, + char *buf, size_t size); +int somc_get_vote_clients(struct votable *votable, char *clients[]); +#endif #endif /* __PMIC_VOTER_H */ diff --git a/include/linux/pn547.h b/include/linux/pn547.h new file mode 100644 index 0000000000000000000000000000000000000000..57fc7f8ecb2a3715366259a07a66303d082551f1 --- /dev/null +++ b/include/linux/pn547.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef _PN547_H_ +#define _PN547_H_ + +#define PN547_DEVICE_NAME "pn547" + +enum pn547_init_deinit_cmd { + PN547_INIT, + PN547_DEINIT, +}; + +enum pn547_set_pwr_cmd { + PN547_SET_PWR_OFF, + PN547_SET_PWR_ON, + PN547_SET_PWR_FWDL, +}; + +enum pn547_state { + PN547_STATE_UNKNOWN, + PN547_STATE_OFF, + PN547_STATE_ON, + PN547_STATE_FWDL, +}; + +struct pn547_i2c_platform_data { + int irq_gpio; + int fwdl_en_gpio; + int ven_gpio; +}; + +#endif + diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 982b93ccfbe4c38b89c52bf0e4f07b7810261f29..491d0694c3760480fd4b1fb0673dbccbecaeec73 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -9,6 +9,11 @@ * * You may use this code as per GPL version 2 */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __LINUX_POWER_SUPPLY_H__ #define __LINUX_POWER_SUPPLY_H__ @@ -249,12 +254,21 @@ enum power_supply_property { POWER_SUPPLY_PROP_HW_CURRENT_MAX, POWER_SUPPLY_PROP_REAL_TYPE, POWER_SUPPLY_PROP_PR_SWAP, - POWER_SUPPLY_PROP_CC_STEP, - POWER_SUPPLY_PROP_CC_STEP_SEL, - POWER_SUPPLY_PROP_SW_JEITA_ENABLED, POWER_SUPPLY_PROP_PD_VOLTAGE_MAX, POWER_SUPPLY_PROP_PD_VOLTAGE_MIN, POWER_SUPPLY_PROP_SDP_CURRENT_MAX, + POWER_SUPPLY_PROP_SKIN_TEMP, + POWER_SUPPLY_PROP_SMART_CHARGING_ACTIVATION, + POWER_SUPPLY_PROP_SMART_CHARGING_INTERRUPTION, + POWER_SUPPLY_PROP_SMART_CHARGING_STATUS, + POWER_SUPPLY_PROP_LRC_ENABLE, + POWER_SUPPLY_PROP_LRC_SOCMAX, + POWER_SUPPLY_PROP_LRC_SOCMIN, + POWER_SUPPLY_PROP_LRC_NOT_STARTUP, + POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT, + POWER_SUPPLY_PROP_CHARGE_FULL_RAW, + POWER_SUPPLY_PROP_TIME_TO_CAP_LEARNING, + POWER_SUPPLY_PROP_INT_CLD, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ @@ -262,6 +276,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_SERIAL_NUMBER, POWER_SUPPLY_PROP_BATTERY_TYPE, + POWER_SUPPLY_PROP_CHARGER_TYPE, }; enum power_supply_type { diff --git a/include/linux/qpnp/pin.h b/include/linux/qpnp/pin.h index 7fb57aa7a77881ea0019d2be1d9d905fd17e7766..0a9648b2a0ea35520edbc997949dd51562fab951 100644 --- a/include/linux/qpnp/pin.h +++ b/include/linux/qpnp/pin.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* Mode select */ #define QPNP_PIN_MODE_DIG_IN 0 @@ -224,3 +229,5 @@ int qpnp_pin_config(int gpio, struct qpnp_pin_cfg *param); * For such cases, use of_get_gpio() or friends instead. */ int qpnp_pin_map(const char *name, uint32_t pmic_pin); + +int qpnp_get_pin_config(int gpio, struct qpnp_pin_cfg *param); diff --git a/include/linux/qpnp/pwm.h b/include/linux/qpnp/pwm.h index 020f18b2cc4bcd0e6ecdffe84391d9c62c298e34..7eaa7225f0ddeea4f7f8b7f811aec685b749b4ad 100644 --- a/include/linux/qpnp/pwm.h +++ b/include/linux/qpnp/pwm.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __QPNP_PWM_H__ #define __QPNP_PWM_H__ @@ -134,6 +139,7 @@ struct lut_params { int lut_pause_lo; int ramp_step_ms; int flags; + bool use_duration; }; #if IS_ENABLED(CONFIG_PWM_QPNP) @@ -155,6 +161,38 @@ int pwm_lut_config(struct pwm_device *pwm, int period_us, int pwm_config_us(struct pwm_device *pwm, int duty_us, int period_us); +/* + * lut_config: LUT config + * @hi_index: LUT high index for ramp + * @lo_index: LUT low index for ramp + * @pause_hi: pause multiplier at high index + * @pause_lo: pause multiplier at low index + * @ramp_step_ms: time before loading next LUT pattern [ms] + * @lut: LUT array + * @flags: control flags (PM_PWM_LUT_XXX) + */ +#define INDEX_MAX_EACH_LED 8 +struct lut_config { + int hi_index; + int lo_index; + int lut_pause_hi; + int lut_pause_lo; + int ramp_step_ms; + int lut[INDEX_MAX_EACH_LED]; + int flags; +}; + +int pwm_config_lut(struct pwm_device *pwm, + struct lut_config *pwm_lut); + +int pwm_start_lut_ramp(struct pwm_device *pwm, int ramp_control); + +int pwm_config_period_value(struct pwm_device *pwm, + struct pwm_period_config *pwm_p, int pwm_value); + +int pwm_get_max_pwm_value(struct pwm_device *pwm); +void pwm_set_max_pwm_value(struct pwm_device *pwm, int max); + #else static inline int pwm_config_period(struct pwm_device *pwm, struct pwm_period_config *pwm_p) diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h index af25f0c0136995b6c02217a40c48cdb2afc08631..030dabc177cb1f791537e85bb958987a3fda84fd 100644 --- a/include/linux/qpnp/qpnp-adc.h +++ b/include/linux/qpnp/qpnp-adc.h @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * Qualcomm PMIC QPNP ADC driver header file * @@ -380,6 +385,8 @@ enum qpnp_adc_channel_scaling_param { * %SCALE_QRD_SKUT1_BATT_THERM: Conversion to temperature(decidegC) based on * btm parameters for SKUT1 * %SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp + * %SCALE_THERM_100K_PULLUP_DECI: Returns temperature in decidegC. + * Uses a mapping table with 100K pullup. * %SCALE_NONE: Do not use this scaling type. */ enum qpnp_adc_scale_fn_type { @@ -397,6 +404,7 @@ enum qpnp_adc_scale_fn_type { SCALE_NCP_03WF683_THERM, SCALE_QRD_SKUT1_BATT_THERM, SCALE_PMI_CHG_TEMP = 16, + SCALE_THERM_100K_PULLUP_DECI, SCALE_NONE, }; @@ -1570,6 +1578,26 @@ int32_t qpnp_adc_scale_therm_pu2(struct qpnp_vadc_chip *dev, int32_t adc_code, const struct qpnp_adc_properties *adc_prop, const struct qpnp_vadc_chan_properties *chan_prop, struct qpnp_vadc_result *chan_rslt); +/** + * qpnp_adc_scale_therm_pu2_decidegc() - Scales the pre-calibrated digital + * output of an ADC to the ADC reference and compensates for the + * gain and offset. + * Returns the temperature of the therm in decidegC. + * It uses a mapping table computed for a 100K pull-up. + * Pull-up2 is an internal pull-up on the AMUX of 100K. + * @dev: Structure device for qpnp vadc + * @adc_code: pre-calibrated digital output of the ADC. + * @adc_prop: adc properties of the pm8xxx adc such as bit resolution, + * reference voltage. + * @chan_prop: individual channel properties to compensate the i/p scaling, + * slope and offset. + * @chan_rslt: physical result to be stored. + */ +int32_t qpnp_adc_scale_therm_pu2_decidegc(struct qpnp_vadc_chip *dev, + int32_t adc_code, + const struct qpnp_adc_properties *adc_prop, + const struct qpnp_vadc_chan_properties *chan_prop, + struct qpnp_vadc_result *chan_rslt); /** * qpnp_adc_scale_therm_ncp03() - Scales the pre-calibrated digital output * of an ADC to the ADC reference and compensates for the @@ -1712,6 +1740,31 @@ int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *dev, int32_t qpnp_adc_tm_scale_voltage_therm_pu2(struct qpnp_vadc_chip *dev, const struct qpnp_adc_properties *adc_prop, uint32_t reg, int64_t *result); +/** + * qpnp_adc_tm_scale_therm_voltage_pu2_decidegc() - Performs reverse calibration + * and convert given temperature to voltage on supported + * thermistor channels using 100k pull-up. + * @dev: Structure device for qpnp vadc + * @adc_prop: adc properties of the qpnp adc such as bit resolution, + * reference voltage. + * @param: The input temperature values. + */ +int32_t qpnp_adc_tm_scale_therm_voltage_pu2_decidegc(struct qpnp_vadc_chip *dev, + const struct qpnp_adc_properties *adc_properties, + struct qpnp_adc_tm_config *param); +/** + * qpnp_adc_tm_scale_voltage_therm_pu2_decidegc() - Performs reverse calibration + * and converts the given ADC code to temperature for + * thermistor channels using 100k pull-up. + * @dev: Structure device for qpnp vadc + * @adc_prop: adc properties of the qpnp adc such as bit resolution, + * reference voltage. + * @reg: The input ADC code. + * @result: The physical measurement temperature on the thermistor. + */ +int32_t qpnp_adc_tm_scale_voltage_therm_pu2_decidegc(struct qpnp_vadc_chip *dev, + const struct qpnp_adc_properties *adc_prop, + uint32_t reg, int64_t *result); /** * qpnp_adc_usb_scaler() - Performs reverse calibration on the low/high * voltage threshold values passed by the client. @@ -1983,6 +2036,12 @@ static inline int32_t qpnp_adc_scale_therm_pu2(struct qpnp_vadc_chip *vadc, const struct qpnp_vadc_chan_properties *chan_prop, struct qpnp_vadc_result *chan_rslt) { return -ENXIO; } +static inline int32_t qpnp_adc_scale_therm_pu2_decidegc( + struct qpnp_vadc_chip *dev, int32_t adc_code, + const struct qpnp_adc_properties *adc_prop, + const struct qpnp_vadc_chan_properties *chan_prop, + struct qpnp_vadc_result *chan_rslt) +{ return -ENXIO; } static inline int32_t qpnp_adc_scale_therm_ncp03(struct qpnp_vadc_chip *vadc, int32_t adc_code, const struct qpnp_adc_properties *adc_prop, @@ -2040,6 +2099,16 @@ static inline int32_t qpnp_adc_tm_scale_voltage_therm_pu2( const struct qpnp_adc_properties *adc_prop, uint32_t reg, int64_t *result) { return -ENXIO; } +static inline int32_t qpnp_adc_tm_scale_therm_voltage_pu2_decidegc( + struct qpnp_vadc_chip *dev, + const struct qpnp_adc_properties *adc_properties, + struct qpnp_adc_tm_config *param) +{ return -ENXIO; } +static inline int32_t qpnp_adc_tm_scale_voltage_therm_pu2_decidegc( + struct qpnp_vadc_chip *dev, + const struct qpnp_adc_properties *adc_prop, + uint32_t reg, int64_t *result) +{ return -ENXIO; } static inline int32_t qpnp_adc_smb_btm_rscaler(struct qpnp_vadc_chip *dev, struct qpnp_adc_tm_btm_param *param, uint32_t *low_threshold, uint32_t *high_threshold) diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h index bbc4625a2d391b305747d14afa9cd89436910c77..b025df5682590b2623bf2d76ea6275297272a85b 100644 --- a/include/linux/qpnp/qpnp-revid.h +++ b/include/linux/qpnp/qpnp-revid.h @@ -252,7 +252,6 @@ struct pmic_revid_data { u8 pmic_subtype; const char *pmic_name; int fab_id; - int tp_rev; }; #ifdef CONFIG_QPNP_REVID diff --git a/include/linux/ramdump_mem_desc.h b/include/linux/ramdump_mem_desc.h new file mode 100644 index 0000000000000000000000000000000000000000..0945836a6db9e6b726e4989bb176fbfebf85aa4d --- /dev/null +++ b/include/linux/ramdump_mem_desc.h @@ -0,0 +1,38 @@ +/* + * Author: Nandhakumar Rangasamy + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __RAMDUMP_MEM_DESC_H_ +#define __RAMDUMP_MEM_DESC_H_ + +#define MEM_DESC_NAME_SIZE 32 + +enum { + MEM_DESC_PLATFORM = 0, + MEM_DESC_CORE +}; + +struct mem_desc { + u64 phys_addr; + u64 size; + u8 name[MEM_DESC_NAME_SIZE]; + u32 flags; + u32 reserved; +} __attribute__ ((__packed__)); + +void ramdump_add_mem_desc(struct mem_desc *); +void ramdump_remove_mem_desc(struct mem_desc *); + +#endif diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 9d3eda39bcd25bd1a2775c80f8dd58c7640600df..60d15a080d7c3dcde45cf458df5632dfc5b36ac2 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -37,7 +37,7 @@ void rcu_cpu_stall_reset(void); /* * Note a virtualization-based context switch. This is simply a * wrapper around rcu_note_context_switch(), which allows TINY_RCU - * to save a few bytes. The caller must have disabled interrupts. + * to save a few bytes. */ static inline void rcu_virt_note_context_switch(int cpu) { diff --git a/include/linux/rdtags.h b/include/linux/rdtags.h new file mode 100644 index 0000000000000000000000000000000000000000..6e3689f12cbfcbd25d1432c04ff7cc0920a777c6 --- /dev/null +++ b/include/linux/rdtags.h @@ -0,0 +1,49 @@ +/* + * + * Author: Nilsson, Stefan 2 + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __RAMDUMP_TAGS_H_ +#define __RAMDUMP_TAGS_H_ + +#include + +int rdtags_remove_tag(const char *name); +int rdtags_add_tag(const char *name, const unsigned char *data, + const size_t size); +int rdtags_get_tag_data(const char *name, unsigned char *data, size_t *size); +void rdtags_clear_tags(void); + +#define rdtags_add_tag_string(x, y) rdtags_add_tag(x, y, sizeof(y)) +#define rdtags_add_tag_type(x, y) \ + rdtags_add_tag(x, (unsigned char *)&y, sizeof(y)) + +#define rdtags_tag_symbol(name) \ +({ \ + char data[32] = {0}; \ + snprintf(data, sizeof(data), "0x%lx", \ + (unsigned long)__pa(&name)); \ + rdtags_add_tag(#name, data, strnlen(data, sizeof(data))); \ +}) + +/** + * struct rdtags_platform_data - Ramdump Tags platform data + * @platform_init: Function that will be called after rdtags is loaded + */ +struct rdtags_platform_data { + int (*platform_init)(int mode); + int ramdump_mode; +}; +#endif diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 734ae72d3c16227e524b1684df43ca046e641ed1..5af39f7c7f9b5cc0f09ce5bbd1510164728c5778 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -31,6 +31,11 @@ * in normal mode for loads > 10mA and in IDLE mode for load <= 10mA. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __LINUX_REGULATOR_CONSUMER_H_ #define __LINUX_REGULATOR_CONSUMER_H_ @@ -163,6 +168,18 @@ struct regulator_bulk_data { int ret; }; +/** + * struct regulator_ocp_notification: event notification structure + * @notify: pointer to client function to call when ocp event is detected. + * notify function runs in interrupt context. + * @ctxt: client-specific context pointer + * + */ +struct regulator_ocp_notification { + void (*notify)(void *); + void *ctxt; +}; + #if defined(CONFIG_REGULATOR) /* regulator get and put */ @@ -259,6 +276,9 @@ int regulator_get_hardware_vsel_register(struct regulator *regulator, unsigned *vsel_mask); int regulator_list_hardware_vsel(struct regulator *regulator, unsigned selector); +/* regulator register ocp notification */ +int regulator_register_ocp_notification(struct regulator *regulator, + struct regulator_ocp_notification *ocp_notification); /* regulator notifier block */ int regulator_register_notifier(struct regulator *regulator, @@ -523,6 +543,13 @@ static inline int regulator_list_hardware_vsel(struct regulator *regulator, return -EOPNOTSUPP; } +static inline int regulator_register_ocp_notification( + struct regulator *regulator, + struct regulator_ocp_notification *ocp_notification) +{ + return 0; +} + static inline int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb) { diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 9cee86d33f86ebb6280ecd71ce61afb191d6ed7e..36eeb954ad97c2f766cd720eca9e5cce01fef7f1 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -11,6 +11,11 @@ * * Regulator Driver Interface. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __LINUX_REGULATOR_DRIVER_H_ #define __LINUX_REGULATOR_DRIVER_H_ @@ -119,6 +124,8 @@ struct regulator_linear_range { * function should return the worst case. * @set_soft_start: Enable soft start for the regulator. * + * @register_ocp_notification: Register the notification for ocp. + * * @set_suspend_voltage: Set the voltage for the regulator when the system * is suspended. * @set_suspend_enable: Mark the regulator as enabled when the system is @@ -191,6 +198,10 @@ struct regulator_ops { int (*set_bypass)(struct regulator_dev *dev, bool enable); int (*get_bypass)(struct regulator_dev *dev, bool *enable); + /* register ocp notification */ + int (*register_ocp_notification) (struct regulator_dev *, + struct regulator_ocp_notification *notification); + /* the operations below are for configuration of regulator state when * its parent PMIC enters a global STANDBY/HIBERNATE state */ diff --git a/include/linux/regulator/qpnp-labibb-regulator.h b/include/linux/regulator/qpnp-labibb-regulator.h index 33985afeb6e9e10316d47631fab7e75a34a895ed..955498eaa1152389c00dd7600ec0daf2501076a4 100644 --- a/include/linux/regulator/qpnp-labibb-regulator.h +++ b/include/linux/regulator/qpnp-labibb-regulator.h @@ -9,16 +9,124 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _QPNP_LABIBB_REGULATOR_H #define _QPNP_LABIBB_REGULATOR_H +#define SOMC_LABIBB_REGULATOR_ORG_IMPL + +#include + enum labibb_notify_event { - LAB_VREG_OK = 1, + LAB_VREG_OK = 1, LAB_VREG_NOT_OK, }; int qpnp_labibb_notifier_register(struct notifier_block *nb); int qpnp_labibb_notifier_unregister(struct notifier_block *nb); -#endif +#ifdef CONFIG_SOMC_LCD_OCP_ENABLED +bool qpnp_labibb_ocp_check(void); +#else +static inline bool qpnp_labibb_ocp_check(void) +{ + return false; +} +#endif /* CONFIG_SOMC_LCD_OCP_ENABLED */ + + +#ifdef SOMC_LABIBB_REGULATOR_ORG_IMPL +/** This API is used to set precharge of LAB regulator + * regulator: the reglator device + * time: precharge time + * en: precharge control enable or not + */ +int qpnp_lab_set_precharge(struct regulator *regulator, u32 time, bool en); + +/** This API is used to set soft-start of LAB regulator + * regulator: the reglator device + * time: soft start time + */ +int qpnp_lab_set_soft_start(struct regulator *regulator, u32 time); + +/** This API is used to set pull-down of LAB regulator + * regulator: the reglator device + * en: pull-down enable or not + * strength: strength pull-down + */ +int qpnp_lab_set_pull_down(struct regulator *regulator, u8 strength); + +/** This API is used to set current max of LAB regulator + * regulator: the reglator device + * limit: current max of LAB regulator + */ +int qpnp_lab_set_current_max(struct regulator *regulator, u32 limit); + +/** This API is used to set soft-start of IBB regulator + * regulator: the reglator device + * time: soft start time + */ +int qpnp_ibb_set_soft_start(struct regulator *regulator, u32 time); + +/** This API is used to set pull-down of IBB regulator + * regulator: the reglator device + * en: pull-down enable or not + * strength: strength pull-down + */ +int qpnp_ibb_set_pull_down(struct regulator *regulator, u8 strength); + +/** This API is used to set current max of IBB regulator + * regulator: the reglator device + * limit: current max of IBB regulator + */ +int qpnp_ibb_set_current_max(struct regulator *regulator, u32 limit); +#else +static inline int qpnp_lab_set_precharge(struct regulator *regulator, + u32 time, bool en) +{ + return -ENODEV; +} + +static inline int qpnp_lab_set_soft_start(struct regulator *regulator, + u32 time) +{ + return -ENODEV; +} + +static inline int qpnp_lab_set_pull_down(struct regulator *regulator, + u8 strength) +{ + return -ENODEV; +} + +static inline int qpnp_lab_set_current_max(struct regulator *regulator, + u32 limit) +{ + return -ENODEV; +} + +static inline int qpnp_ibb_set_soft_start(struct regulator *regulator, + u32 time) +{ + return -ENODEV; +} + +static inline int qpnp_ibb_set_pull_down(struct regulator *regulator, + u8 strength) +{ + return -ENODEV; +} + +static inline int qpnp_ibb_set_current_max(struct regulator *regulator, + u32 limit) +{ + return -ENODEV; +} +#endif /* SOMC_LABIBB_REGULATOR_ORG_IMPL */ + +#endif /* _QPNP_LABIBB_REGULATOR_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index baf107821d9ae4c775b1dab19c0815abcbc80af6..57042d91ae9c3a56d6724adf5d128083cc7ef932 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2481,7 +2481,6 @@ extern void do_set_cpus_allowed(struct task_struct *p, extern int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask); -extern bool cpupri_check_rt(void); #else static inline void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask) @@ -2494,10 +2493,6 @@ static inline int set_cpus_allowed_ptr(struct task_struct *p, return -EINVAL; return 0; } -static inline bool cpupri_check_rt(void) -{ - return false; -} #endif struct sched_load { diff --git a/include/linux/sim_detect.h b/include/linux/sim_detect.h new file mode 100644 index 0000000000000000000000000000000000000000..ccf3fc47079feff65a921620b27254aede18a364 --- /dev/null +++ b/include/linux/sim_detect.h @@ -0,0 +1,37 @@ +/* include/linux/sim_detect.h + * + * Author: Atsushi Iyogi + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef _LINUX_SIM_DETECT_H +#define _LINUX_SIM_DETECT_H + +struct device; + +struct sim_detect_gpio_event { + int index; + int gpio; + int active_low; + const char *desc; + int debounce_interval; + unsigned int irq; +}; + +struct sim_detect_platform_data { + int n_events; + struct sim_detect_gpio_event *events; +}; + +#endif diff --git a/include/linux/soc/qcom/smd-rpm.h b/include/linux/soc/qcom/smd-rpm.h index ebdabd669d932a4eb203ca8e851288543e346c14..0dfd47a0fbe7bb7fc1114bb259ef8287fb46148b 100644 --- a/include/linux/soc/qcom/smd-rpm.h +++ b/include/linux/soc/qcom/smd-rpm.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __QCOM_SMD_RPM_H__ #define __QCOM_SMD_RPM_H__ diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h index d0cb6d189a0a02bd28459c7b143229563f23c4e4..1f7e8e3cdfb52cf807c74dd0061e6c87b7166f24 100644 --- a/include/linux/soc/qcom/smd.h +++ b/include/linux/soc/qcom/smd.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ #ifndef __QCOM_SMD_H__ #define __QCOM_SMD_H__ diff --git a/include/linux/soc/qcom/smem.h b/include/linux/soc/qcom/smem.h index 785e196ee2cae6f1b0ec48fad8816db3839aa943..b2e9000df445ea2487da099d0909bc4d31f5997b 100644 --- a/include/linux/soc/qcom/smem.h +++ b/include/linux/soc/qcom/smem.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __QCOM_SMEM_H__ #define __QCOM_SMEM_H__ diff --git a/include/linux/suspend.h b/include/linux/suspend.h index c59803dc68de7e7a1d4805b83dabad5a5b00aaf8..357bb7592953b986be6c158156184fc3edebe59a 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _LINUX_SUSPEND_H #define _LINUX_SUSPEND_H @@ -7,6 +12,10 @@ #include #include #include +#ifdef CONFIG_PM_WAKEUP_TIMES +#include +#include +#endif #include #ifdef CONFIG_VT @@ -51,6 +60,20 @@ enum suspend_stat_step { SUSPEND_RESUME }; +#ifdef CONFIG_PM_WAKEUP_TIMES +struct stats_wakeup_time { + ktime_t start; + ktime_t end; +}; + +struct suspend_stats_queue { + int resume_done; + wait_queue_head_t wait_queue; +}; + +extern struct suspend_stats_queue suspend_stats_queue; +#endif + struct suspend_stats { int success; int fail; @@ -69,6 +92,16 @@ struct suspend_stats { int errno[REC_FAILED_NUM]; int last_failed_step; enum suspend_stat_step failed_steps[REC_FAILED_NUM]; +#ifdef CONFIG_PM_WAKEUP_TIMES + struct stats_wakeup_time suspend_min_time; + struct stats_wakeup_time suspend_max_time; + struct stats_wakeup_time suspend_last_time; + ktime_t suspend_avg_time; + struct stats_wakeup_time resume_min_time; + struct stats_wakeup_time resume_max_time; + struct stats_wakeup_time resume_last_time; + ktime_t resume_avg_time; +#endif }; extern struct suspend_stats suspend_stats; diff --git a/include/linux/tick.h b/include/linux/tick.h index d1162e9b7a36a436d2affc9490da12b2aa415640..1732697ea419a04fb97e4642d9271d32a665f521 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -105,7 +105,6 @@ extern void tick_nohz_idle_enter(void); extern void tick_nohz_idle_exit(void); extern void tick_nohz_irq_exit(void); extern ktime_t tick_nohz_get_sleep_length(void); -extern unsigned long tick_nohz_get_idle_calls(void); extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time); #else /* !CONFIG_NO_HZ_COMMON */ diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index f0f1793cfa498b3fa6fcf791f53404c4cac88ae3..25247220b4b7ddf3f336077b105ab42271475a05 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h @@ -29,6 +29,7 @@ */ struct tk_read_base { struct clocksource *clock; + cycle_t (*read)(struct clocksource *cs); cycle_t mask; cycle_t cycle_last; u32 mult; diff --git a/include/linux/tof_sensor.h b/include/linux/tof_sensor.h new file mode 100644 index 0000000000000000000000000000000000000000..c2dd90a22339fa295347894139950f4c25ec890e --- /dev/null +++ b/include/linux/tof_sensor.h @@ -0,0 +1,26 @@ +/* + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef TOF_SENSOR_H +#define TOF_SENSOR_H + +/* + * tof sensor power control. + */ +enum tof_sensor_power_control { + TOF_SENSOR_POWER_CONTROL_OFF, + TOF_SENSOR_POWER_CONTROL_ON, +}; + +#endif /* TOF_SENSOR_H */ diff --git a/include/linux/uid_stat.h b/include/linux/uid_stat.h new file mode 100644 index 0000000000000000000000000000000000000000..7c8ff2d13369f1ebe6530a4c66ecf15ff8f8e710 --- /dev/null +++ b/include/linux/uid_stat.h @@ -0,0 +1,34 @@ +/* include/linux/uid_stat.h + * + * Copyright (C) 2008-2009 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. + * + */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ + +#ifndef __uid_stat_h +#define __uid_stat_h + +/* Contains definitions for resource tracking per uid. */ + +#ifdef CONFIG_UID_STAT +int uid_stat_tcp_snd(uid_t uid, int size); +int uid_stat_tcp_rcv(uid_t uid, int size); +#else +#define uid_stat_tcp_snd(uid, size) do {} while (0); +#define uid_stat_tcp_rcv(uid, size) do {} while (0); +#endif + +#endif /* _LINUX_UID_STAT_H */ diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index dff7adbc60bb873f37d6a6092bca0063107ddaeb..e888eb9a2eb91a1a794a10d8b95a1b07e3be244a 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -579,9 +579,9 @@ extern void usb_ep0_reinit(struct usb_device *); ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) #define EndpointRequest \ - ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8) + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) #define EndpointOutRequest \ - ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8) + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) /* class requests from the USB 2.0 hub spec, table 11-15 */ /* GetBusState and SetHubDescriptor are optional, omitted */ diff --git a/include/linux/usb/host_ext_event.h b/include/linux/usb/host_ext_event.h new file mode 100644 index 0000000000000000000000000000000000000000..b21477dbad94f90156bd53a1503c7da50a0d3c06 --- /dev/null +++ b/include/linux/usb/host_ext_event.h @@ -0,0 +1,30 @@ + /* include/linux/usb/host_ext_event.h + * + * USB host event handling function + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2013 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + + +#ifndef __HOST_EXT_EVENT_H__ +#define __HOST_EXT_EVENT_H__ + +enum usb_host_ext_event { + USB_HOST_EXT_EVENT_NONE = -1, + USB_HOST_EXT_EVENT_VBUS_DROP, + USB_HOST_EXT_EVENT_INSUFFICIENT_POWER, +}; + +extern int host_send_uevent(enum usb_host_ext_event event); + +#endif diff --git a/include/linux/usb/usb_qdss.h b/include/linux/usb/usb_qdss.h index f2b8782528a835674ac74a5f13bfe17986256c64..e01e6781eb21ca74a7cf10179fce257846429b1d 100644 --- a/include/linux/usb/usb_qdss.h +++ b/include/linux/usb/usb_qdss.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, 2017, The Linux Foundation. All rights reserved. +/* 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 @@ -15,9 +15,6 @@ #include -#define USB_QDSS_CH_MDM "qdss_mdm" -#define USB_QDSS_CH_MSM "qdss" - struct qdss_request { char *buf; int length; diff --git a/include/linux/usb_bam.h b/include/linux/usb_bam.h index b5b9edaab783cf3f8f87a23145c8e132a49ae02c..e65fb12c141016e3b806d23cf66c2f1c420a1a17 100644 --- a/include/linux/usb_bam.h +++ b/include/linux/usb_bam.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2016, 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 @@ -191,7 +191,7 @@ struct usb_bam_pipe_connect { }; /** - * struct msm_usb_bam_data: pipe connection information + * struct msm_usb_bam_platform_data: pipe connection information * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be * either src BAM or dst BAM * @usb_bam_num_pipes: max number of pipes to use. @@ -211,7 +211,7 @@ struct usb_bam_pipe_connect { * can work at in bam2bam mode when connected to SS host. * @enable_hsusb_bam_on_boot: Enable HSUSB BAM (non-NDP) on bootup itself */ -struct msm_usb_bam_data { +struct msm_usb_bam_platform_data { u8 max_connections; int usb_bam_num_pipes; phys_addr_t usb_bam_fifo_baseaddr; diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index e0c47f8b06bf897104be82295ba2979380fdc12b..c93364b861d9e284e6393f31fe2934641c31f6ac 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -38,7 +38,6 @@ struct vregs_level { }; struct wcnss_wlan_config { - bool wcn_external_gpio_support; int use_48mhz_xo; int is_pronto_vadc; int is_pronto_v3; @@ -75,8 +74,6 @@ enum { #define HAVE_WCNSS_CAL_DOWNLOAD 1 #define HAVE_CBC_DONE 1 #define HAVE_WCNSS_RX_BUFF_COUNT 1 -#define HAVE_WCNSS_SNOC_HIGH_FREQ_VOTING 1 -#define HAVE_WCNSS_5G_DISABLE 1 #define WLAN_MAC_ADDR_SIZE (6) #define WLAN_RF_REG_ADDR_START_OFFSET 0x3 #define WLAN_RF_REG_DATA_START_OFFSET 0xf @@ -135,14 +132,12 @@ void wcnss_riva_dump_pmic_regs(void); int wcnss_xo_auto_detect_enabled(void); u32 wcnss_get_wlan_rx_buff_count(void); int wcnss_wlan_iris_xo_mode(void); -int wcnss_wlan_dual_band_disabled(void); void wcnss_flush_work(struct work_struct *work); void wcnss_flush_delayed_work(struct delayed_work *dwork); void wcnss_init_work(struct work_struct *work , void *callbackptr); void wcnss_init_delayed_work(struct delayed_work *dwork , void *callbackptr); int wcnss_get_iris_name(char *iris_version); void wcnss_dump_stack(struct task_struct *task); -void wcnss_snoc_vote(bool clk_chk_en); #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE void wcnss_log_debug_regs_on_bite(void); diff --git a/include/linux/zpool.h b/include/linux/zpool.h index 2e97b7707dffcb9f3067e4c574e3c73700469146..0c567847e28fddaa82c90d53021c4f5743410747 100644 --- a/include/linux/zpool.h +++ b/include/linux/zpool.h @@ -7,6 +7,11 @@ * storage pool implementations. Typically, this is used to * store compressed memory. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _ZPOOL_H_ #define _ZPOOL_H_ @@ -60,6 +65,9 @@ void zpool_unmap_handle(struct zpool *pool, unsigned long handle); u64 zpool_get_total_size(struct zpool *pool); +unsigned long zpool_compact(struct zpool *pool); + +unsigned long zpool_get_num_compacted(struct zpool *zpool); /** * struct zpool_driver - driver implementation for zpool @@ -101,6 +109,10 @@ struct zpool_driver { void (*unmap)(void *pool, unsigned long handle); u64 (*total_size)(void *pool); + + unsigned long (*compact)(void *pool); + + unsigned long (*get_num_compacted)(void *pool); }; void zpool_register_driver(struct zpool_driver *driver); diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h index 2c8b651147e0b96ec55941210efca13bd619e91b..ee70669c5ab1d7b0fa150287ac551c0ec072d1ff 100644 --- a/include/media/msm_cam_sensor.h +++ b/include/media/msm_cam_sensor.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __LINUX_MSM_CAM_SENSOR_H #define __LINUX_MSM_CAM_SENSOR_H @@ -84,15 +89,6 @@ struct msm_ir_cut_cfg_data_t32 { enum msm_ir_cut_cfg_type_t cfg_type; }; -struct msm_laser_led_cfg_data_t32 { - enum msm_laser_led_cfg_type_t cfg_type; - compat_uptr_t setting; - compat_uptr_t debug_reg; - uint32_t debug_reg_size; - uint16_t i2c_addr; - enum i2c_freq_mode_t i2c_freq_mode; -}; - struct eeprom_read_t32 { compat_uptr_t dbuffer; uint32_t num_bytes; @@ -122,6 +118,9 @@ struct msm_eeprom_cfg_data32 { }; struct msm_camera_i2c_seq_reg_setting32 { +/* extension begin */ + uint16_t slave_addr; +/* extension end */ compat_uptr_t reg_setting; uint16_t size; enum msm_camera_i2c_reg_addr_type addr_type; @@ -256,6 +255,13 @@ struct msm_flash_cfg_data_t32 { } cfg; }; +/* extension begin */ +struct msm_sensor_event_data32 { + uint32_t sof_count; + struct compat_timeval mono_timestamp; +}; +/* extension end */ + #define VIDIOC_MSM_ACTUATOR_CFG32 \ _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_actuator_cfg_data32) @@ -285,10 +291,7 @@ struct msm_flash_cfg_data_t32 { #define VIDIOC_MSM_IR_CUT_CFG32 \ _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_ir_cut_cfg_data_t32) - -#define VIDIOC_MSM_LASER_LED_CFG32 \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_laser_led_cfg_data_t32) - #endif #endif + diff --git a/include/net/activity_stats.h b/include/net/activity_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..3e85979109e0815e4234e46206512dd186b2088d --- /dev/null +++ b/include/net/activity_stats.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 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. + * + * Author: Mike Chan (mike@android.com) + */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ + +#ifndef __activity_stats_h +#define __activity_stats_h + +#ifdef CONFIG_NET_ACTIVITY_STATS +void activity_stats_update(void); +#else +#define activity_stats_update(void) {} +#endif + +#endif /* _NET_ACTIVITY_STATS_H */ diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index f9bdfb09657902b6068e0e00689e9e9ea78231a9..814a13d22df683d79ee0e1686b6783989abee7bd 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -21,7 +21,6 @@ struct route_info { #include #include #include -#include #include #include #include @@ -210,11 +209,4 @@ static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt, return daddr; } -static inline bool rt6_duplicate_nexthop(struct rt6_info *a, struct rt6_info *b) -{ - return a->dst.dev == b->dst.dev && - a->rt6i_idev == b->rt6i_idev && - ipv6_addr_equal(&a->rt6i_gateway, &b->rt6i_gateway) && - !lwtunnel_cmp_encap(a->dst.lwtstate, b->dst.lwtstate); -} #endif diff --git a/include/net/xfrm.h b/include/net/xfrm.h index c81d806e415f2b6b9e9d254a23ef5729763ffb6e..d18cbafc3455546f67d0ca292d576a3e4a6e4f43 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -947,6 +947,10 @@ struct xfrm_dst { struct flow_cache_object flo; struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; int num_pols, num_xfrms; +#ifdef CONFIG_XFRM_SUB_POLICY + struct flowi *origin; + struct xfrm_selector *partner; +#endif u32 xfrm_genid; u32 policy_genid; u32 route_mtu_cached; @@ -962,6 +966,12 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) dst_release(xdst->route); if (likely(xdst->u.dst.xfrm)) xfrm_state_put(xdst->u.dst.xfrm); +#ifdef CONFIG_XFRM_SUB_POLICY + kfree(xdst->origin); + xdst->origin = NULL; + kfree(xdst->partner); + xdst->partner = NULL; +#endif } #endif diff --git a/include/soc/qcom/camera2.h b/include/soc/qcom/camera2.h index 5a61d2b372c3a6da2f4d6d6412b0cf97c55a7084..f409ac88d336f481d0ce750631e2a4444b094f8a 100644 --- a/include/soc/qcom/camera2.h +++ b/include/soc/qcom/camera2.h @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __CAMERA2_H__ #define __CAMERA2_H__ @@ -87,6 +92,10 @@ struct msm_camera_gpio_conf { uint8_t cam_gpio_common_tbl_size; struct gpio *cam_gpio_req_tbl; uint8_t cam_gpio_req_tbl_size; +/* extension begin */ + struct msm_gpio_set_tbl *cam_gpio_set_tbl; + uint8_t cam_gpio_set_tbl_size; +/* extension end */ uint32_t gpio_no_mux; uint32_t *camera_off_table; uint8_t camera_off_table_size; diff --git a/include/soc/qcom/last_logs.h b/include/soc/qcom/last_logs.h new file mode 100644 index 0000000000000000000000000000000000000000..4e1da68a6d772457e56f98d3a5a4d5f767e7afc5 --- /dev/null +++ b/include/soc/qcom/last_logs.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#ifndef _LAST_LOGS_H +#define _LAST_LOGS_H + +#ifdef CONFIG_LAST_LOGS + +#ifdef CONFIG_MSM_TZ_LOG +#include +#endif /* CONFIG_MSM_TZ_LOG */ + +#define MAX_LAST_LOGS_REGIONS 16 +#define LAST_LOGS_VERSION 0x00010000 +#define LAST_LOGS_MAGIC 0x442474D4 +#define MAX_NAME_LENGTH 16 + +typedef struct __packed { + char name[MAX_NAME_LENGTH]; + uint32_t offset; + uint32_t size; + uint32_t reserved; +} last_logs_region; + +typedef struct __packed { + uint32_t version; + uint32_t magic; + uint32_t num_regions; + uint32_t reserved[3]; + last_logs_region regions[MAX_LAST_LOGS_REGIONS]; +} last_logs_header; + +struct last_logs_data { + void *addr; + uint32_t size; + struct dentry *debugfs_file; +}; + +#endif /* CONFIG_LAST_LOGS */ +#endif /* _LAST_LOGS_H */ diff --git a/include/soc/qcom/last_logs_tz.h b/include/soc/qcom/last_logs_tz.h new file mode 100644 index 0000000000000000000000000000000000000000..735b4f27b3dacfba624014b222a4fccbbee40de7 --- /dev/null +++ b/include/soc/qcom/last_logs_tz.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#ifndef _LAST_LOGS_TZ_H +#define _LAST_LOGS_TZ_H + +#ifdef CONFIG_MSM_TZ_LOG +int format_tzbsp_log(void *, size_t, void **, uint32_t *); +#endif /* CONFIG_MSM_TZ_LOG */ + +#endif /* _LAST_LOGS_TZ_H */ diff --git a/include/soc/qcom/memory_dump.h b/include/soc/qcom/memory_dump.h index f1170dbb3569dc2aa9fe8bfdd6899ef582d80e02..79b75ca2691545c91f37b0e66ca35794f30763c7 100644 --- a/include/soc/qcom/memory_dump.h +++ b/include/soc/qcom/memory_dump.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __MSM_MEMORY_DUMP_H #define __MSM_MEMORY_DUMP_H @@ -118,12 +123,21 @@ struct msm_dump_entry { #ifdef CONFIG_QCOM_MEMORY_DUMP_V2 extern int msm_dump_data_register(enum msm_dump_table_ids id, struct msm_dump_entry *entry); +#ifdef CONFIG_RAMDUMP_TAGS +extern int dump_table_ramdump_setup(void); +#endif #else static inline int msm_dump_data_register(enum msm_dump_table_ids id, struct msm_dump_entry *entry) { return -ENOSYS; } +#ifdef CONFIG_RAMDUMP_TAGS +static inline int dump_table_ramdump_setup(void) +{ + return -ENOSYS; +} +#endif #endif #endif diff --git a/include/soc/qcom/minidump.h b/include/soc/qcom/minidump.h index d5970cfef64359067e6edb098d60c91098cee49e..5eb18cb1a365a98f7ce14ade57270f7a004ea757 100644 --- a/include/soc/qcom/minidump.h +++ b/include/soc/qcom/minidump.h @@ -39,16 +39,11 @@ struct md_region { extern int msm_minidump_add_region(const struct md_region *entry); /* Sets to true, if minidump table is initialized */ extern bool minidump_enabled; -extern void dump_stack_minidump(u64 sp); #else static inline int msm_minidump_add_region(const struct md_region *entry) { /* Return quietly, if minidump is not supported */ return 0; } - -static inline void dump_stack_minidump(u64 sp) {} #endif - - #endif diff --git a/include/soc/qcom/qseecomi.h b/include/soc/qcom/qseecomi.h index e199978302bfaa2b6e161897ca62591acc5e45af..6497d962e347ee5d7d14c1d6badf424aa5dd9609 100644 --- a/include/soc/qcom/qseecomi.h +++ b/include/soc/qcom/qseecomi.h @@ -336,7 +336,7 @@ __packed struct qseecom_client_send_fsm_key_req { __packed struct qseecom_continue_blocked_request_ireq { uint32_t qsee_cmd_id; - uint32_t app_or_session_id; /*legacy: app_id; smcinvoke: session_id*/ + uint32_t app_id; }; @@ -681,9 +681,6 @@ __packed struct qseecom_continue_blocked_request_ireq { #define TZ_OS_CONTINUE_BLOCKED_REQUEST_ID \ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x04) -#define TZ_OS_CONTINUE_BLOCKED_REQUEST_SMCINVOKE_ID \ - TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x07) - #define TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL) diff --git a/include/soc/qcom/ramdump.h b/include/soc/qcom/ramdump.h index 4e23ccf269a7145aeee9a1e8228eb36de79abef1..50a17c8ad6051d40e0d9553f888e9f12b8b4f38b 100644 --- a/include/soc/qcom/ramdump.h +++ b/include/soc/qcom/ramdump.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, 2017 The Linux Foundation. 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 and @@ -16,7 +16,6 @@ struct device; struct ramdump_segment { - char *name; unsigned long address; void *v_address; unsigned long size; @@ -29,8 +28,6 @@ extern int do_ramdump(void *handle, struct ramdump_segment *segments, int nsegments); extern int do_elf_ramdump(void *handle, struct ramdump_segment *segments, int nsegments); -extern int do_minidump(void *handle, struct ramdump_segment *segments, - int nsegments); #else static inline void *create_ramdump_device(const char *dev_name, diff --git a/include/soc/qcom/scm.h b/include/soc/qcom/scm.h index f0a3124dae002a4b33589369452fbbda01cf962b..ad57eda97f9d0d394058c36ad1b44eefbf00670e 100644 --- a/include/soc/qcom/scm.h +++ b/include/soc/qcom/scm.h @@ -95,7 +95,7 @@ struct scm_desc { u64 x5; }; -#if defined(CONFIG_QCOM_SCM) || defined(CONFIG_QCOM_SCM_QCPE) +#ifdef CONFIG_QCOM_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); @@ -121,9 +121,9 @@ extern s32 scm_call_atomic5_3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3, 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, u64 *scm_ret); +extern int scm_get_feat_version(u32 feat); extern bool is_scm_armv8(void); -extern int scm_restore_sec_cfg(u32 device_id, u32 spare, u64 *scm_ret); +extern int scm_restore_sec_cfg(u32 device_id, u32 spare, int *scm_ret); extern u32 scm_io_read(phys_addr_t address); extern int scm_io_write(phys_addr_t address, u32 val); extern bool scm_is_secure_device(void); @@ -205,7 +205,7 @@ static inline int scm_is_call_available(u32 svc_id, u32 cmd_id) return 0; } -static inline int scm_get_feat_version(u32 feat, u64 *scm_ret) +static inline int scm_get_feat_version(u32 feat) { return 0; } @@ -215,7 +215,7 @@ static inline bool is_scm_armv8(void) return true; } -static inline int scm_restore_sec_cfg(u32 device_id, u32 spare, u64 *scm_ret) +static inline int scm_restore_sec_cfg(u32 device_id, u32 spare, int *scm_ret) { return 0; } @@ -230,7 +230,7 @@ static inline int scm_io_write(phys_addr_t address, u32 val) return 0; } -static inline bool scm_is_secure_device(void) +inline bool scm_is_secure_device(void) { return false; } diff --git a/include/soc/qcom/security_status.h b/include/soc/qcom/security_status.h new file mode 100644 index 0000000000000000000000000000000000000000..d554d14382f8c628a59fe255abcd90ecc1da281d --- /dev/null +++ b/include/soc/qcom/security_status.h @@ -0,0 +1,31 @@ +/** + * @file security_status.h + * + * @brief Gets security status of device by + * checking oemandroidboot.securityflags + * + * @author Nandhakumar Rangasamy (nandhakumar.x.rangasamy@sonymobile.com) + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __SECURITY_STATUS_H +#define __SECURITY_STATUS_H + +#define SECURITY_ON 1 +#define SECURITY_OFF 0 + +#ifdef CONFIG_SECURITY_STATUS +int get_security_status(int *status); +#else +static inline int get_security_status(int *status) +{ + return -ENOTSUP; +} +#endif /* CONFIG_SECURITY_STATUS */ +#endif /* __SECURITY_STATUS_H */ diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 9110963d0e9fbe3fb1d5baf01fe03c681a853bee..2e8d71754c984743c469818a079677af28446ec1 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -96,10 +96,6 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm660") #define early_machine_is_sda660() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda660") -#define early_machine_is_sdm636() \ - of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm636") -#define early_machine_is_sda636() \ - of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda636") #define early_machine_is_sdm658() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm658") #define early_machine_is_sda658() \ @@ -146,8 +142,6 @@ #define early_machine_is_msmhamster() 0 #define early_machine_is_sdm660() 0 #define early_machine_is_sda660() 0 -#define early_machine_is_sdm636() 0 -#define early_machine_is_sda636() 0 #define early_machine_is_sdm658() 0 #define early_machine_is_sda658() 0 #define early_machine_is_sdm630() 0 @@ -212,7 +206,6 @@ enum msm_cpu { MSM_CPU_HAMSTER, MSM_CPU_660, MSM_CPU_630, - MSM_CPU_636, }; struct msm_soc_info { diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h index 9a4d013b363cc14c3e786036935432d868bdefa2..da0c07cccba8956c50818dd7f3d34e75bd06b1cf 100644 --- a/include/soc/qcom/subsystem_restart.h +++ b/include/soc/qcom/subsystem_restart.h @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __SUBSYS_RESTART_H #define __SUBSYS_RESTART_H @@ -17,6 +22,8 @@ #include #include +#define SUBSYS_CRASH_REASON_LEN 512 + struct subsys_device; extern struct bus_type subsys_bus_type; @@ -134,12 +141,28 @@ extern void subsys_set_crash_status(struct subsys_device *dev, enum crash_status crashed); extern enum crash_status subsys_get_crash_status(struct subsys_device *dev); extern void subsys_set_error(struct subsys_device *dev, const char *error_msg); + +extern int subsystem_crash_reason(const char *name, char *reason); +#if defined(CONFIG_DEBUG_FS) +extern void update_crash_reason(struct subsys_device *dev, char *, int); +#else +static inline void update_crash_reason(struct subsys_device *dev, + char *reason, int size) { } +#endif void notify_proxy_vote(struct device *device); void notify_proxy_unvote(struct device *device); void complete_err_ready(struct subsys_device *subsys); extern int wait_for_shutdown_ack(struct subsys_desc *desc); #else +static inline void update_crash_reason(struct subsys_device *dev, + char *reason, int size) { } + +static inline int subsystem_crash_reason(const char *name, char *reason) +{ + return 0; +} + static inline int subsys_get_restart_level(struct subsys_device *dev) { return 0; diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 21b30bf7c74cebd7b7980535c5941e710bb50f02..a51f0b731168df98abe0fe392da9a7344640bea5 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _APR_AUDIO_V2_H_ @@ -446,88 +451,6 @@ struct adm_param_data_v5 { */ } __packed; - -struct param_data_v6 { - /* Unique ID of the module. */ - u32 module_id; - /* Unique ID of the instance. */ - u16 instance_id; - /* Reserved for future enhancements. - * This field must be set to zero. - */ - u16 reserved; - /* Unique ID of the parameter. */ - u32 param_id; - /* Data size of the param_id/module_id combination. - * This value is a - * multiple of 4 bytes. - */ - u32 param_size; -} __packed; - -/* ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1 command is used to set - * calibration data to the ADSP Matrix Mixer the payload is - * of struct adm_cmd_set_mtmx_params_v1. - * - * ADM_CMD_GET_MTMX_STRTR_DEV_PARAMS_V1 can be used to get - * the calibration data from the ADSP Matrix Mixer and - * ADM_CMDRSP_GET_MTMX_STRTR_DEV_PARAMS_V1 is the response - * ioctl to ADM_CMD_GET_MTMX_STRTR_DEV_PARAMS_V1. - */ -#define ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1 0x00010367 -#define ADM_CMD_GET_MTMX_STRTR_DEV_PARAMS_V1 0x00010368 -#define ADM_CMDRSP_GET_MTMX_STRTR_DEV_PARAMS_V1 0x00010369 - -/* Payload of the #define ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1 command. - * If the data_payload_addr_lsw and data_payload_addr_msw element - * are NULL, a series of struct param_data_v6 structures immediately - * follows, whose total size is payload_size bytes. - */ -struct adm_cmd_set_mtmx_params_v1 { - struct apr_hdr hdr; - /* LSW of parameter data payload address.*/ - u32 payload_addr_lsw; - - /* MSW of parameter data payload address.*/ - u32 payload_addr_msw; - - /* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS - * command. - * If mem_map_handle is zero it implies the message is in - * the payload - */ - u32 mem_map_handle; - - /* Size in bytes of the variable payload accompanying this - * message or in shared memory. This is used for parsing - * the parameter payload. - */ - u32 payload_size; - - /* COPP ID/Device ID */ - u16 copp_id; - - /* For alignment, must be set to 0 */ - u16 reserved; -} __packed; - -struct enable_param_v6 { - /* - * Specifies whether the Audio processing module is enabled. - * This parameter is generic/common parameter to configure or - * determine the state of any audio processing module. - */ - struct param_data_v6 param; - - /* @values 0 : Disable 1: Enable */ - uint32_t enable; -} __packed; - -/* Defined in ADSP as VOICE_MODULE_TX_STREAM_LIMITER but - * used for RX stream limiter on matrix input to ADM. - */ -#define ADM_MTMX_MODULE_STREAM_LIMITER 0x00010F15 - #define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213 #define ASM_STREAM_PP_EVENT 0x00013214 #define ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE 0x13333 @@ -707,29 +630,6 @@ struct audproc_softvolume_params { */ #define AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT 0x00010913 -/* ID of the Channel Mixer module, which is used to configure - * channel-mixer related parameters. - * This module supports the AUDPROC_CHMIXER_PARAM_ID_COEFF parameter ID. - */ -#define AUDPROC_MODULE_ID_CHMIXER 0x00010341 - -/* ID of the Coefficient parameter used by AUDPROC_MODULE_ID_CHMIXER to - *configure the channel mixer weighting coefficients. - */ -#define AUDPROC_CHMIXER_PARAM_ID_COEFF 0x00010342 - -/* Payload of the per-session, per-device parameter data of the - * #ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 command or - * #ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V6 command. - * Immediately following this structure are param_size bytes of parameter - * data. The structure and size depend on the module_id/param_id pair. - */ -struct adm_pspd_param_data_t { - uint32_t module_id; - uint32_t param_id; - uint16_t param_size; - uint16_t reserved; -} __packed; struct audproc_mfc_output_media_fmt { struct adm_cmd_set_pp_params_v5 params; @@ -916,6 +816,7 @@ struct adm_session_copp_gain_v5 { /* Payload of the #ADM_CMD_MATRIX_MUTE_V5 command*/ struct adm_cmd_matrix_mute_v5 { + struct apr_hdr hdr; u32 matrix_id; /* Specifies whether the matrix ID is Audio Rx (0) or Audio Tx (1). * Use the ADM_MATRIX_ID_AUDIO_RX or ADM_MATRIX_ID_AUDIOX @@ -3772,6 +3673,8 @@ struct afe_lpass_core_shared_clk_config_command { #define VPM_TX_DM_RFECNS_COPP_TOPOLOGY 0x00010F86 #define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX 0x10015002 #define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE 0x10028000 +#define VOICE_TOPOLOGY_LVVEFQ_TX_SM 0x1000BFF0 +#define VOICE_TOPOLOGY_LVVEFQ_TX_DM 0x1000BFF1 /* Memory map regions command payload used by the * #ASM_CMD_SHARED_MEM_MAP_REGIONS ,#ADM_CMD_SHARED_MEM_MAP_REGIONS @@ -4007,14 +3910,6 @@ struct asm_softvolume_params { u32 rampingcurve; } __packed; -struct asm_stream_pan_ctrl_params { - uint16_t num_output_channels; - uint16_t num_input_channels; - uint16_t output_channel_map[8]; - uint16_t input_channel_map[8]; - uint32_t gain[64]; -} __packed; - #define ASM_END_POINT_DEVICE_MATRIX 0 #define PCM_CHANNEL_NULL 0 @@ -7074,6 +6969,12 @@ struct asm_stream_cmd_open_read_compressed { 0x11000000 #define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_MCH_PEAK_VOL \ 0x0001031B +#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_RX_MCH_IIR_COPP_MBDRC_V3 \ + 0x11000004 +#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP_SOMC_HP \ + 0x11000006 +#define ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_RX_MCH_FIR_IIR_COPP_MBDRC_V3 \ + 0x11000009 #define ADM_CMD_COPP_OPENOPOLOGY_ID_MIC_MONO_AUDIO_COPP 0x00010315 #define ADM_CMD_COPP_OPENOPOLOGY_ID_MIC_STEREO_AUDIO_COPP 0x00010316 #define AUDPROC_COPPOPOLOGY_ID_MCHAN_IIR_AUDIO 0x00010715 @@ -7915,48 +7816,6 @@ struct asm_volume_ctrl_lr_chan_gain { /*< Linear gain in Q13 format for the right channel.*/ } __packed; -struct audproc_chmixer_param_coeff { - uint32_t index; - uint16_t num_output_channels; - uint16_t num_input_channels; -} __packed; - - -/* ID of the Multichannel Volume Control parameters used by - * AUDPROC_MODULE_ID_VOL_CTRL. - */ -#define AUDPROC_PARAM_ID_MULTICHANNEL_GAIN 0x00010713 - -/* Payload of the AUDPROC_PARAM_ID_MULTICHANNEL_GAIN channel type/gain - * pairs used by the Volume Control module. - * This structure immediately follows the - * audproc_volume_ctrl_multichannel_gain_t structure. - */ -struct audproc_volume_ctrl_channel_type_gain_pair { - uint8_t channel_type; - /* Channel type for which the gain setting is to be applied. */ - - uint8_t reserved1; - uint8_t reserved2; - uint8_t reserved3; - - uint32_t gain; - /* Gain value for this channel in Q28 format. */ -} __packed; - -/* Payload of the AUDPROC_PARAM_ID_MULTICHANNEL_MUTE parameters used by - * the Volume Control module. - */ -struct audproc_volume_ctrl_multichannel_gain { - uint32_t num_channels; - /* Number of channels for which mute configuration is provided. Any - * channels present in the data for which mute configuration is not - * provided are set to unmute. - */ - - struct audproc_volume_ctrl_channel_type_gain_pair *gain_data; - /* Array of channel type/mute setting pairs. */ -} __packed; /* Structure for the mute configuration parameter for a volume control module. */ @@ -9306,6 +9165,7 @@ struct srs_trumedia_params { } __packed; /* SRS TruMedia end */ +#define AUDPROC_PARAM_ID_ENABLE 0x00010904 #define ASM_STREAM_POSTPROC_TOPO_ID_SA_PLUS 0x1000FFFF /* DTS Eagle */ #define AUDPROC_MODULE_ID_DTS_HPX_PREMIX 0x0001077C @@ -9482,6 +9342,45 @@ struct afe_param_id_clip_bank_sel { uint32_t bank_map[AFE_CLIP_MAX_BANKS]; } __packed; +/* SOMC effect start */ +/* Module/Parameter IDs */ +#define ASM_MODULE_ID_SONYBUNDLE 0x10002010 + +#define PARAM_ID_SB_COMMON_USER_PARAM 0x10002011 +#define PARAM_ID_SB_DYNAMICNORMALIZER_USER_PARAM 0x10002012 +#define PARAM_ID_SB_SFORCE_USER_PARAM 0x10002013 +#define PARAM_ID_SB_VPT20_USER_PARAM 0x10002014 +#define PARAM_ID_SB_CLEARPHASE_HP_USER_PARAM 0x10002015 +#define PARAM_ID_SB_CLEARAUDIO_USER_PARAM 0x10002016 +#define PARAM_ID_SB_CLEARAUDIO_VOLUME_PARAM 0x10002017 +#define PARAM_ID_SB_CLEARPHASE_SP_USER_PARAM 0x10002018 +#define PARAM_ID_SB_XLOUD_USER_PARAM 0x10002019 + +#define PARAM_ID_SB_CLEARPHASE_HP_TUNING 0x1000201A +#define PARAM_ID_SB_SFORCE_TUNING 0x1000201B +#define PARAM_ID_SB_CLEARPHASE_SP_TUNING 0x1000201C +#define PARAM_ID_SB_XLOUD_TUNING 0x1000201D + +#define ASM_STREAM_POSTPROC_TOPO_ID_SONY 0x10002101 + +struct clearphase_hp_tuning_params { + unsigned char coefs[2064]; +} __packed; + +struct s_force_tuning_params { + unsigned char coefs[1016]; +} __packed; + +struct clearphase_sp_tuning_params { + unsigned char coefs[2360]; +} __packed; + +struct xloud_tuning_params { + unsigned int level; + unsigned char coefs[512]; +} __packed; +/* SOMC effect end */ + /* ERROR CODES */ /* Success. The operation completed with no errors. */ #define ADSP_EOK 0x00000000 diff --git a/include/sound/jack.h b/include/sound/jack.h index 0d2a334fbeaaf9dce583e9a2440a06774fda29ac..0eaaf0323a94f2f17f5a8135d983c09a8847b6c5 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __SOUND_JACK_H #define __SOUND_JACK_H @@ -64,7 +69,8 @@ enum snd_jack_types { SND_JACK_MICROPHONE2 = 0x0200, SND_JACK_ANC_HEADPHONE = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | SND_JACK_MICROPHONE2, - + SND_JACK_STEREO_MICROPHONE = SND_JACK_MICROPHONE | + SND_JACK_MICROPHONE2, /* Kept separate from switches to facilitate implementation */ SND_JACK_BTN_0 = 0x8000, SND_JACK_BTN_1 = 0x4000, diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h index 65c42ee18914f6dc4f6eb5e79df3aafe11e8ab30..0e3d6b4f5e35dc5bb3f7e355d28c9d44e434cf04 100644 --- a/include/sound/q6adm-v2.h +++ b/include/sound/q6adm-v2.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __Q6_ADM_V2_H__ #define __Q6_ADM_V2_H__ @@ -51,13 +56,6 @@ enum { ADM_CLIENT_ID_MAX, }; -/* ENUM for adm_status & route_status */ -enum adm_status_flags { - ADM_STATUS_CALIBRATION_REQUIRED = 0, - ADM_STATUS_LIMITER, - ADM_STATUS_MAX, -}; - #define MAX_COPPS_PER_PORT 0x8 #define ADM_MAX_CHANNELS 8 @@ -68,7 +66,6 @@ struct route_payload { int app_type[MAX_COPPS_PER_PORT]; int acdb_dev_id[MAX_COPPS_PER_PORT]; int sample_rate[MAX_COPPS_PER_PORT]; - unsigned long route_status[MAX_COPPS_PER_PORT]; unsigned short num_copps; unsigned int session_id; }; @@ -87,6 +84,9 @@ struct msm_pcm_channel_mixer { int channel_weight[ADM_MAX_CHANNELS][ADM_MAX_CHANNELS]; }; +int adm_matrix_mute(int port_id, int session_id, uint32_t ramp_duration, + uint32_t mute_flag_ch1, uint32_t mute_flag_ch2); + int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id, void *srs_params); @@ -107,6 +107,9 @@ int adm_send_params_v5(int port_id, int copp_idx, char *params, int adm_dolby_dap_send_params(int port_id, int copp_idx, char *params, uint32_t params_length); +int adm_ahc_send_params(int port_id, int copp_idx, char *params, + uint32_t params_length); + int adm_open(int port, int path, int rate, int mode, int topology, int perf_mode, uint16_t bits_per_sample, int app_type, int acdbdev_id); @@ -146,13 +149,9 @@ int adm_get_topology_for_port_copp_idx(int port_id, int copp_idx); int adm_get_indexes_from_copp_id(int copp_id, int *port_idx, int *copp_idx); -int adm_set_pspd_matrix_params(int port_id, int copp_idx, - unsigned int session_id, - char *params, uint32_t params_length); - -int adm_set_downmix_params(int port_id, int copp_idx, - unsigned int session_id, char *params, - uint32_t params_length); +int adm_set_stereo_to_custom_stereo(int port_id, int copp_idx, + unsigned int session_id, + char *params, uint32_t params_length); int adm_get_pp_topo_module_list(int port_id, int copp_idx, int32_t param_length, char *params); diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 9ddd02cac9acdbfb701cacb36c437807809a84d8..284b37d14a6c7d2390d35771f12629ed6a36395b 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __Q6_ASM_V2_H__ #define __Q6_ASM_V2_H__ @@ -99,7 +104,7 @@ #define SOFT_PAUSE_ENABLE 1 #define SOFT_PAUSE_DISABLE 0 -#define ASM_ACTIVE_STREAMS_ALLOWED 0x9 +#define ASM_ACTIVE_STREAMS_ALLOWED 0x8 /* Control session is used for mapping calibration memory */ #define ASM_CONTROL_SESSION (ASM_ACTIVE_STREAMS_ALLOWED + 1) @@ -611,14 +616,6 @@ int q6asm_set_softvolume(struct audio_client *ac, int q6asm_set_softvolume_v2(struct audio_client *ac, struct asm_softvolume_params *param, int instance); -/* Set panning and MFC params */ -int q6asm_set_mfc_panning_params(struct audio_client *ac, - struct asm_stream_pan_ctrl_params *pan_param); - -/* Set vol gain pair */ -int q6asm_set_vol_ctrl_gain_pair(struct audio_client *ac, - struct asm_stream_pan_ctrl_params *pan_param); - /* Send left-right channel gain */ int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain); @@ -639,8 +636,7 @@ int q6asm_send_audio_effects_params(struct audio_client *ac, char *params, int q6asm_send_stream_cmd(struct audio_client *ac, struct msm_adsp_event_data *data); -int q6asm_audio_map_shm_fd(struct audio_client *ac, struct ion_client **client, - struct ion_handle **handle, int fd); +int q6asm_send_ion_fd(struct audio_client *ac, int fd); int q6asm_send_rtic_event_ack(struct audio_client *ac, void *param, uint32_t params_length); @@ -693,4 +689,8 @@ uint8_t q6asm_get_stream_id_from_token(uint32_t token); int q6asm_adjust_session_clock(struct audio_client *ac, uint32_t adjust_time_lsw, uint32_t adjust_time_msw); + +/* SOMC added: Send tuning parameter for Sony effect*/ +int sony_hweffect_send_tuning_params(unsigned int effect_id, void *client); + #endif /* __Q6_ASM_H__ */ diff --git a/include/sound/q6core.h b/include/sound/q6core.h index 4f55880d410f1d603f1b41050da23fe64527fd2d..1d81bda4b5134ad24f3536e98f279f1e87cb89f4 100644 --- a/include/sound/q6core.h +++ b/include/sound/q6core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -20,8 +20,6 @@ #define AVCS_CMDRSP_ADSP_EVENT_GET_STATE 0x0001290D bool q6core_is_adsp_ready(void); -int q6core_add_remove_pool_pages(phys_addr_t buf_add, uint32_t bufsz, - uint32_t mempool_id, bool add_pages); #define ADSP_CMD_SET_DTS_EAGLE_DATA_ID 0x00012919 #define DTS_EAGLE_LICENSE_ID 0x00028346 @@ -155,16 +153,4 @@ struct avcs_cmd_deregister_topologies { int32_t core_set_license(uint32_t key, uint32_t module_id); int32_t core_get_license_status(uint32_t module_id); -#define ADSP_MEMORY_MAP_HLOS_PHYSPOOL 4 -#define AVCS_CMD_ADD_POOL_PAGES 0x0001292E -#define AVCS_CMD_REMOVE_POOL_PAGES 0x0001292F - -struct avs_mem_assign_region { - struct apr_hdr hdr; - u32 pool_id; - u32 size; - u32 addr_lsw; - u32 addr_msw; -} __packed; - #endif /* __Q6CORE_H__ */ diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h index ba8c415771b79972e11d9014ef6510d17ad59f9c..1cb11af864662d007f116772d3a61b09c3ca7fce 100644 --- a/include/trace/events/kmem.h +++ b/include/trace/events/kmem.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #undef TRACE_SYSTEM #define TRACE_SYSTEM kmem @@ -214,6 +219,34 @@ TRACE_EVENT(mm_page_free_batched, __entry->cold) ); +TRACE_EVENT(mm_page_alloc_highorder, + + TP_PROTO(struct page *page, unsigned int order, + gfp_t gfp_flags, int migratetype), + + TP_ARGS(page, order, gfp_flags, migratetype), + + TP_STRUCT__entry(__field(struct page *, page) + __field(unsigned int, order) + __field(gfp_t, gfp_flags) + __field(int, migratetype) + ), + + TP_fast_assign( + __entry->page = page; + __entry->order = order; + __entry->gfp_flags = gfp_flags; + __entry->migratetype = migratetype; + ), + + TP_printk("page=%p pfn=%lu order=%d migratetype=%d gfp_flags=%s", + __entry->page, + page_to_pfn(__entry->page), + __entry->order, + __entry->migratetype, + show_gfp_flags(__entry->gfp_flags)) +); + TRACE_EVENT(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, @@ -310,6 +343,25 @@ TRACE_EVENT_CONDITION(mm_page_pcpu_drain, __entry->order, __entry->migratetype) ); +TRACE_EVENT(mm_page_alloc_fail, + + TP_PROTO(int alloc_order), + + TP_ARGS(alloc_order), + + TP_STRUCT__entry( + __field(int, alloc_order) + ), + + TP_fast_assign( + __entry->alloc_order = alloc_order; + ), + + TP_printk("alloc_order=%d pageblock_order=%d", + __entry->alloc_order, + pageblock_order) +); + TRACE_EVENT(mm_page_alloc_extfrag, TP_PROTO(struct page *page, diff --git a/include/trace/events/lmk.h b/include/trace/events/lmk.h new file mode 100644 index 0000000000000000000000000000000000000000..c0c1d7fc884f666495a02a60486ee2c0000932dd --- /dev/null +++ b/include/trace/events/lmk.h @@ -0,0 +1,95 @@ +/* + * License terms: GNU General Public License (GPL) version 2 + * + * Author: Peter Enderborg + */ +/* + * Copyright (C) 2017 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM lmk + +#if !defined(_TRACE_LMK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_LMK_H + +#include +#include + +DECLARE_EVENT_CLASS(lmk_kill, + TP_PROTO(int pid, + const char *comm, + int score, + int size, + int gfp_mask), + TP_ARGS(pid, comm, score, size, gfp_mask), + + TP_STRUCT__entry( + __field(int, pid) + __array(char, comm, TASK_COMM_LEN) + __field(int, score) + __field(int, size) + __field(int, gfp_mask) + ), + + TP_fast_assign( + __entry->pid = pid; + memcpy(__entry->comm, comm, TASK_COMM_LEN); + __entry->score = score; + __entry->size = size; + __entry->gfp_mask = gfp_mask; + ), + + TP_printk("pid=%d comm=%s score=%d size=%d gfp_mask=%d", + __entry->pid, __entry->comm, + __entry->score, __entry->size, + __entry->gfp_mask) + +); + +DEFINE_EVENT(lmk_kill, lmk_sigkill, + TP_PROTO(int pid, + const char *comm, + int score, + int size, + int gfp_mask), + + TP_ARGS(pid, comm, score, size, gfp_mask) +); + +DECLARE_EVENT_CLASS(lmk_remain, + TP_PROTO(int rem, int nr_to_scan, int gfp_mask), + TP_ARGS(rem, nr_to_scan, gfp_mask), + + TP_STRUCT__entry( + __field(int, rem) + __field(int, nr_to_scan) + __field(int, gfp_mask) + ), + + TP_fast_assign( + __entry->rem = rem; + __entry->nr_to_scan = nr_to_scan; + __entry->gfp_mask = gfp_mask; + ), + + TP_printk("rem=%d scan=%d gfp_mask=%d", + __entry->rem, __entry->nr_to_scan, __entry->gfp_mask) + +); + +DEFINE_EVENT(lmk_remain, lmk_remain_scan, + TP_PROTO(int rem, int nr_to_scan, int gfp_mask), + + TP_ARGS(rem, nr_to_scan, gfp_mask) +); + + +#endif /* _TRACE_LMK_H */ + +/* This part must be outside protection */ +#include diff --git a/include/trace/events/oom.h b/include/trace/events/oom.h index 1e974983757eb2e9974d0ac619ff8b8b27a491d5..fd65bba5587ae3e441a580a9712d61eec86560d3 100644 --- a/include/trace/events/oom.h +++ b/include/trace/events/oom.h @@ -27,6 +27,47 @@ TRACE_EVENT(oom_score_adj_update, __entry->pid, __entry->comm, __entry->oom_score_adj) ); +DECLARE_EVENT_CLASS(oom_kill, + TP_PROTO(int pid, + const char *comm, + int score, + unsigned long size, + int gfp_mask), + TP_ARGS(pid, comm, score, size, gfp_mask), + + TP_STRUCT__entry( + __field(int, pid) + __field(const char *, comm) + __field(int, score) + __field(unsigned long, size) + __field(int, gfp_mask) + ), + + TP_fast_assign( + __entry->pid = pid; + __entry->comm = comm; + __entry->score = score; + __entry->size = size; + __entry->gfp_mask = gfp_mask; + ), + + TP_printk("pid=%d comm=%s score=%d size=%ld gfp_mask=%d", + __entry->pid, __entry->comm, + __entry->score, __entry->size, + __entry->gfp_mask) + +); + +DEFINE_EVENT(oom_kill, oom_sigkill, + TP_PROTO(int pid, + const char *comm, + int score, + unsigned long size, + int gfp_mask), + + TP_ARGS(pid, comm, score, size, gfp_mask) +); + #endif /* This part must be outside protection */ diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index a852f2a3701fd17f7755a3b94d5fb1fd56a65727..927c3626edb79dfc1511159ca2b93482d8a983b0 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -83,21 +83,6 @@ struct drm_msm_ext_panel_hdr_metadata { __u32 max_average_light_level; /* max average light level */ }; -/** - * HDR Control - * This encapsulates the HDR metadata as well as a state control - * for the HDR metadata as required by the HDMI spec to send the - * relevant metadata depending on the state of the HDR playback. - * hdr_state: Controls HDR state, takes values ENABLE(1)/DISABLE(0) - * hdr_meta: Metadata sent by the userspace for the HDR clip - */ - -#define DRM_MSM_EXT_PANEL_HDR_CTRL -struct drm_msm_ext_panel_hdr_ctrl { - __u8 hdr_state; /* HDR state */ - struct drm_msm_ext_panel_hdr_metadata hdr_meta; /* HDR metadata */ -}; - /** * HDR sink properties * These are defined as per EDID spec and shall be used by the userspace @@ -234,7 +219,7 @@ struct drm_msm_gem_submit_cmd { __u32 size; /* in, cmdstream size */ __u32 pad; __u32 nr_relocs; /* in, number of submit_reloc's */ - __u64 relocs; /* in, ptr to array of submit_reloc's */ + __u64 __user relocs; /* in, ptr to array of submit_reloc's */ }; /* Each buffer referenced elsewhere in the cmdstream submit (ie. the @@ -274,8 +259,8 @@ struct drm_msm_gem_submit { __u32 fence; /* out */ __u32 nr_bos; /* in, number of submit_bo's */ __u32 nr_cmds; /* in, number of submit_cmd's */ - __u64 bos; /* in, ptr to array of submit_bo's */ - __u64 cmds; /* in, ptr to array of submit_cmd's */ + __u64 __user bos; /* in, ptr to array of submit_bo's */ + __u64 __user cmds; /* in, ptr to array of submit_cmd's */ __s32 fence_fd; /* gap for the fence_fd which is upstream */ __u32 queueid; /* in, submitqueue id */ }; diff --git a/include/uapi/drm/sde_drm.h b/include/uapi/drm/sde_drm.h index 71159cb377d8d79048c4c2f7c2c0632922563d5e..bef841446247bca0b8cf0f2c1bee5d0d2d33af19 100644 --- a/include/uapi/drm/sde_drm.h +++ b/include/uapi/drm/sde_drm.h @@ -337,14 +337,4 @@ struct sde_drm_wb_cfg { uint64_t modes; }; -/** - * Define extended power modes supported by the SDE connectors. - */ -#define SDE_MODE_DPMS_ON 0 -#define SDE_MODE_DPMS_LP1 1 -#define SDE_MODE_DPMS_LP2 2 -#define SDE_MODE_DPMS_STANDBY 3 -#define SDE_MODE_DPMS_SUSPEND 4 -#define SDE_MODE_DPMS_OFF 5 - #endif /* _SDE_DRM_H_ */ diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 3d912dd57c081ca39716f8b265c3eb1fdc37b29f..096f66addda145e114cef970176d9220a017b075 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -524,6 +524,7 @@ header-y += msm_dsps.h header-y += msm-core-interface.h header-y += msm_thermal_ioctl.h header-y += android_pmem.h +header-y += tof_sensor.h header-y += ipa_qmi_service_v01.h header-y += rmnet_ipa_fd_ioctl.h header-y += msm_ipa.h diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 5539933b3491b6ec98353c560a957ab9ad3f5544..7668b5791c91ad0eb9fe05ff6ba5a7a2e19be66a 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -37,56 +37,9 @@ enum { BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE), }; -/** - * enum flat_binder_object_shifts: shift values for flat_binder_object_flags - * @FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT: shift for getting scheduler policy. - * - */ -enum flat_binder_object_shifts { - FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT = 9, -}; - -/** - * enum flat_binder_object_flags - flags for use in flat_binder_object.flags - */ -enum flat_binder_object_flags { - /** - * @FLAT_BINDER_FLAG_PRIORITY_MASK: bit-mask for min scheduler priority - * - * These bits can be used to set the minimum scheduler priority - * at which transactions into this node should run. Valid values - * in these bits depend on the scheduler policy encoded in - * @FLAT_BINDER_FLAG_SCHED_POLICY_MASK. - * - * For SCHED_NORMAL/SCHED_BATCH, the valid range is between [-20..19] - * For SCHED_FIFO/SCHED_RR, the value can run between [1..99] - */ +enum { FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, - /** - * @FLAT_BINDER_FLAG_ACCEPTS_FDS: whether the node accepts fds. - */ FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, - /** - * @FLAT_BINDER_FLAG_SCHED_POLICY_MASK: bit-mask for scheduling policy - * - * These two bits can be used to set the min scheduling policy at which - * transactions on this node should run. These match the UAPI - * scheduler policy values, eg: - * 00b: SCHED_NORMAL - * 01b: SCHED_FIFO - * 10b: SCHED_RR - * 11b: SCHED_BATCH - */ - FLAT_BINDER_FLAG_SCHED_POLICY_MASK = - 3U << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT, - - /** - * @FLAT_BINDER_FLAG_INHERIT_RT: whether the node inherits RT policy - * - * Only when set, calls into this node will inherit a real-time - * scheduling policy from the caller (for synchronous transactions). - */ - FLAT_BINDER_FLAG_INHERIT_RT = 0x800, }; #ifdef BINDER_IPC_32BIT @@ -233,19 +186,6 @@ struct binder_version { #define BINDER_CURRENT_PROTOCOL_VERSION 8 #endif -/* - * Use with BINDER_GET_NODE_DEBUG_INFO, driver reads ptr, writes to all fields. - * Set ptr to NULL for the first call to get the info for the first node, and - * then repeat the call passing the previously returned value to get the next - * nodes. ptr will be 0 when there are no more nodes. - */ -struct binder_node_debug_info { - binder_uintptr_t ptr; - binder_uintptr_t cookie; - __u32 has_strong_ref; - __u32 has_weak_ref; -}; - #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) @@ -253,7 +193,6 @@ struct binder_node_debug_info { #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) #define BINDER_THREAD_EXIT _IOW('b', 8, __s32) #define BINDER_VERSION _IOWR('b', 9, struct binder_version) -#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) /* * NOTE: Two special error codes you should check for when calling diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 88956276c8ab95036241543381c5eba13a8605d9..2f8983b511fd832024f884e45927dbf03dad8138 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -12,6 +12,11 @@ * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _UAPI_INPUT_EVENT_CODES_H #define _UAPI_INPUT_EVENT_CODES_H @@ -749,11 +754,11 @@ #define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ #define SW_LINEIN_INSERT 0x0d /* set = inserted */ #define SW_MUTE_DEVICE 0x0e /* set = device disabled */ -#define SW_HPHL_OVERCURRENT 0x0f /* set = over current on left hph */ -#define SW_HPHR_OVERCURRENT 0x10 /* set = over current on right hph */ -#define SW_MICROPHONE2_INSERT 0x11 /* set = inserted */ -#define SW_UNSUPPORT_INSERT 0x12 /* set = unsupported device inserted */ -#define SW_MAX 0x20 +#define SW_HPHL_OVERCURRENT 0x1c /* set = over current on left hph */ +#define SW_HPHR_OVERCURRENT 0x1d /* set = over current on right hph */ +#define SW_UNSUPPORT_INSERT 0x1e /* set = unsupported device inserted */ +#define SW_MICROPHONE2_INSERT 0x1f /* set = inserted */ +#define SW_MAX 0x1f #define SW_CNT (SW_MAX+1) /* diff --git a/include/uapi/linux/ipa_qmi_service_v01.h b/include/uapi/linux/ipa_qmi_service_v01.h index dc46ee0f29a2bc8a887e25a65e91be8af3ed6642..60867630e1a1bc3287a1b4060cc8d0c277854cfc 100644 --- a/include/uapi/linux/ipa_qmi_service_v01.h +++ b/include/uapi/linux/ipa_qmi_service_v01.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -47,12 +47,6 @@ #define QMI_IPA_MAX_FILTERS_EX_V01 128 #define QMI_IPA_MAX_PIPES_V01 20 #define QMI_IPA_MAX_APN_V01 8 -#define QMI_IPA_MAX_PER_CLIENTS_V01 64 -/* Currently max we can use is only 1. But for scalability purpose - * we are having max value as 8. - */ -#define QMI_IPA_MAX_CLIENT_DST_PIPES_V01 8 -#define QMI_IPA_MAX_UL_FIREWALL_RULES_V01 64 #define IPA_INT_MAX ((int)(~0U>>1)) #define IPA_INT_MIN (-IPA_INT_MAX - 1) @@ -990,16 +984,6 @@ struct ipa_fltr_installed_notif_req_msg_v01 { * failure, the Rule Ids in this list must be set to a reserved * index (255). */ - - /* Optional */ - /* List of destination pipe IDs. */ - uint8_t dst_pipe_id_valid; - /* Must be set to true if dst_pipe_id is being passed. */ - uint32_t dst_pipe_id_len; - /* Must be set to # of elements in dst_pipe_id. */ - uint32_t dst_pipe_id[QMI_IPA_MAX_CLIENT_DST_PIPES_V01]; - /* Provides the list of destination pipe IDs for a source pipe. */ - }; /* Message */ /* Response Message; This is the message that is exchanged between the @@ -1638,273 +1622,6 @@ struct ipa_install_fltr_rule_resp_ex_msg_v01 { */ }; /* Message */ -/* - * Request Message; Requests the modem IPA driver to enable or - * disable collection of per client statistics. - */ -struct ipa_enable_per_client_stats_req_msg_v01 { - - /* Mandatory */ - /* Collect statistics per client; */ - uint8_t enable_per_client_stats; - /* - * Indicates whether to start or stop collecting - * per client statistics. - */ -}; /* Message */ - -/* - * Response Message; Requests the modem IPA driver to enable or disable - * collection of per client statistics. - */ -struct ipa_enable_per_client_stats_resp_msg_v01 { - - /* Mandatory */ - /* Result Code */ - struct ipa_qmi_response_type_v01 resp; - /* Standard response type. */ -}; /* Message */ - -struct ipa_per_client_stats_info_type_v01 { - - uint32_t client_id; - /* - * Id of the client on APPS processor side for which Modem processor - * needs to send uplink/downlink statistics. - */ - - uint32_t src_pipe_id; - /* - * IPA consumer pipe on which client on APPS side sent uplink - * data to modem. - */ - - uint64_t num_ul_ipv4_bytes; - /* - * Accumulated number of uplink IPv4 bytes for a client. - */ - - uint64_t num_ul_ipv6_bytes; - /* - * Accumulated number of uplink IPv6 bytes for a client. - */ - - uint64_t num_dl_ipv4_bytes; - /* - * Accumulated number of downlink IPv4 bytes for a client. - */ - - uint64_t num_dl_ipv6_bytes; - /* - * Accumulated number of downlink IPv6 byes for a client. - */ - - - uint32_t num_ul_ipv4_pkts; - /* - * Accumulated number of uplink IPv4 packets for a client. - */ - - uint32_t num_ul_ipv6_pkts; - /* - * Accumulated number of uplink IPv6 packets for a client. - */ - - uint32_t num_dl_ipv4_pkts; - /* - * Accumulated number of downlink IPv4 packets for a client. - */ - - uint32_t num_dl_ipv6_pkts; - /* - * Accumulated number of downlink IPv6 packets for a client. - */ -}; /* Type */ - -/* - * Request Message; Requests the modem IPA driver to provide statistics - * for a givenclient. - */ -struct ipa_get_stats_per_client_req_msg_v01 { - - /* Mandatory */ - /* Client id */ - uint32_t client_id; - /* - * Id of the client on APPS processor side for which Modem processor - * needs to send uplink/downlink statistics. if client id is specified - * as 0xffffffff, then Q6 will send the stats for all the clients of - * the specified source pipe. - */ - - /* Mandatory */ - /* Source pipe id */ - uint32_t src_pipe_id; - /* - * IPA consumer pipe on which client on APPS side sent uplink - * data to modem. In future, this implementation can be extended - * to provide 0xffffffff as the source pipe id, where Q6 will send - * the stats of all the clients across all different tethered-pipes. - */ - - /* Optional */ - /* Reset client statistics. */ - uint8_t reset_stats_valid; - /* Must be set to true if reset_stats is being passed. */ - uint8_t reset_stats; - /* - * Option to reset the statistics currently collected by modem for this - * particular client. - */ -}; /* Message */ - -/* - * Response Message; Requests the modem IPA driver to provide statistics - * for a given client. - */ -struct ipa_get_stats_per_client_resp_msg_v01 { - - /* Mandatory */ - /* Result Code */ - struct ipa_qmi_response_type_v01 resp; - /* Standard response type. */ - - /* Optional */ - /* Per clients Statistics List */ - uint8_t per_client_stats_list_valid; - /* Must be set to true if per_client_stats_list is being passed. */ - uint32_t per_client_stats_list_len; - /* Must be set to # of elements in per_client_stats_list. */ - struct ipa_per_client_stats_info_type_v01 - per_client_stats_list[QMI_IPA_MAX_PER_CLIENTS_V01]; - /* - * List of all per client statistics that are retrieved. - */ -}; /* Message */ - -struct ipa_ul_firewall_rule_type_v01 { - - enum ipa_ip_type_enum_v01 ip_type; - /* - * IP type for which this rule is applicable. - * The driver must identify the filter table (v6 or v4), and this - * field is essential for that. Values: - * - QMI_IPA_IP_TYPE_INVALID (0) -- Invalid IP type identifier - * - QMI_IPA_IP_TYPE_V4 (1) -- IPv4 type - * - QMI_IPA_IP_TYPE_V6 (2) -- IPv6 type - */ - - struct ipa_filter_rule_type_v01 filter_rule; - /* - * Rules in the filter specification. These rules are the - * ones that are matched against fields in the packet. - * Currently we only send IPv6 whitelist rules to Q6. - */ -}; /* Type */ - -/* - * Request Message; Requestes remote IPA driver to install uplink - * firewall rules. - */ -struct ipa_configure_ul_firewall_rules_req_msg_v01 { - - /* Optional */ - /* Uplink Firewall Specification */ - uint32_t firewall_rules_list_len; - /* Must be set to # of elements in firewall_rules_list. */ - struct ipa_ul_firewall_rule_type_v01 - firewall_rules_list[QMI_IPA_MAX_UL_FIREWALL_RULES_V01]; - /* - * List of uplink firewall specifications of filters that must be - * installed. - */ - - uint32_t mux_id; - /* - * QMAP Mux ID. As a part of the QMAP protocol, - * several data calls may be multiplexed over the same physical - * transport channel. This identifier is used to identify one - * such data call. The maximum value for this identifier is 255. - */ - - /* Optional */ - uint8_t disable_valid; - /* Must be set to true if enable is being passed. */ - uint8_t disable; - /* - * Indicates whether uplink firewall needs to be enabled or disabled. - */ - - /* Optional */ - uint8_t are_blacklist_filters_valid; - /* Must be set to true if are_blacklist_filters is being passed. */ - uint8_t are_blacklist_filters; - /* - * Indicates whether the filters received as part of this message are - * blacklist filters. i.e. drop uplink packets matching these rules. - */ -}; /* Message */ - -/* - * Response Message; Requestes remote IPA driver to install - * uplink firewall rules. - */ -struct ipa_configure_ul_firewall_rules_resp_msg_v01 { - - /* Mandatory */ - /* Result Code */ - struct ipa_qmi_response_type_v01 resp; - /* - * Standard response type. - * Standard response type. Contains the following data members: - * qmi_result_type -- QMI_RESULT_SUCCESS or QMI_RESULT_FAILURE - * qmi_error_type -- Error code. Possible error code values are - * described in the error codes section of each message definition. - */ -}; /* Message */ - -enum ipa_ul_firewall_status_enum_v01 { - IPA_UL_FIREWALL_STATUS_ENUM_MIN_ENUM_VAL_V01 = -2147483647, - /* To force a 32 bit signed enum. Do not change or use*/ - QMI_IPA_UL_FIREWALL_STATUS_SUCCESS_V01 = 0, - /* Indicates that the uplink firewall rules - * are configured successfully. - */ - QMI_IPA_UL_FIREWALL_STATUS_FAILURE_V01 = 1, - /* Indicates that the uplink firewall rules - * are not configured successfully. - */ - IPA_UL_FIREWALL_STATUS_ENUM_MAX_ENUM_VAL_V01 = 2147483647 - /* To force a 32 bit signed enum. Do not change or use*/ -}; - -struct ipa_ul_firewall_config_result_type_v01 { - - enum ipa_ul_firewall_status_enum_v01 is_success; - /* - * Indicates whether the uplink firewall rules are configured - * successfully. - */ - - uint32_t mux_id; - /* - * QMAP Mux ID. As a part of the QMAP protocol, - * several data calls may be multiplexed over the same physical - * transport channel. This identifier is used to identify one - * such data call. The maximum value for this identifier is 255. - */ -}; - -/* - * Indication Message; Requestes remote IPA driver to install - * uplink firewall rules. - */ -struct ipa_configure_ul_firewall_rules_ind_msg_v01 { - - struct ipa_ul_firewall_config_result_type_v01 result; -}; /* Message */ - - /*Service Message Definition*/ #define QMI_IPA_INDICATION_REGISTER_REQ_V01 0x0020 #define QMI_IPA_INDICATION_REGISTER_RESP_V01 0x0020 @@ -1938,13 +1655,6 @@ struct ipa_configure_ul_firewall_rules_ind_msg_v01 { #define QMI_IPA_INIT_MODEM_DRIVER_CMPLT_RESP_V01 0x0035 #define QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_V01 0x0037 #define QMI_IPA_INSTALL_FILTER_RULE_EX_RESP_V01 0x0037 -#define QMI_IPA_ENABLE_PER_CLIENT_STATS_REQ_V01 0x0038 -#define QMI_IPA_ENABLE_PER_CLIENT_STATS_RESP_V01 0x0038 -#define QMI_IPA_GET_STATS_PER_CLIENT_REQ_V01 0x0039 -#define QMI_IPA_GET_STATS_PER_CLIENT_RESP_V01 0x0039 -#define QMI_IPA_INSTALL_UL_FIREWALL_RULES_REQ_V01 0x003A -#define QMI_IPA_INSTALL_UL_FIREWALL_RULES_RESP_V01 0x003A -#define QMI_IPA_INSTALL_UL_FIREWALL_RULES_IND_V01 0x003A /* add for max length*/ #define QMI_IPA_INIT_MODEM_DRIVER_REQ_MAX_MSG_LEN_V01 134 @@ -1953,7 +1663,7 @@ struct ipa_configure_ul_firewall_rules_ind_msg_v01 { #define QMI_IPA_INDICATION_REGISTER_RESP_MAX_MSG_LEN_V01 7 #define QMI_IPA_INSTALL_FILTER_RULE_REQ_MAX_MSG_LEN_V01 22369 #define QMI_IPA_INSTALL_FILTER_RULE_RESP_MAX_MSG_LEN_V01 783 -#define QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_MAX_MSG_LEN_V01 870 +#define QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_MAX_MSG_LEN_V01 834 #define QMI_IPA_FILTER_INSTALLED_NOTIF_RESP_MAX_MSG_LEN_V01 7 #define QMI_IPA_MASTER_DRIVER_INIT_COMPLETE_IND_MAX_MSG_LEN_V01 7 #define QMI_IPA_DATA_USAGE_QUOTA_REACHED_IND_MAX_MSG_LEN_V01 15 @@ -1986,15 +1696,6 @@ struct ipa_configure_ul_firewall_rules_ind_msg_v01 { #define QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_MAX_MSG_LEN_V01 22685 #define QMI_IPA_INSTALL_FILTER_RULE_EX_RESP_MAX_MSG_LEN_V01 523 -#define QMI_IPA_ENABLE_PER_CLIENT_STATS_REQ_MAX_MSG_LEN_V01 4 -#define QMI_IPA_ENABLE_PER_CLIENT_STATS_RESP_MAX_MSG_LEN_V01 7 - -#define QMI_IPA_GET_STATS_PER_CLIENT_REQ_MAX_MSG_LEN_V01 18 -#define QMI_IPA_GET_STATS_PER_CLIENT_RESP_MAX_MSG_LEN_V01 3595 - -#define QMI_IPA_INSTALL_UL_FIREWALL_RULES_REQ_MAX_MSG_LEN_V01 9875 -#define QMI_IPA_INSTALL_UL_FIREWALL_RULES_RESP_MAX_MSG_LEN_V01 7 -#define QMI_IPA_INSTALL_UL_FIREWALL_RULES_IND_MAX_MSG_LEN_V01 11 /* Service Object Accessor */ #endif/* IPA_QMI_SERVICE_V01_H */ diff --git a/include/uapi/linux/kernel-page-flags.h b/include/uapi/linux/kernel-page-flags.h index 5da5f8751ce7dc082a4a99cfe29e7d2eb7f6ba5a..1692fde58c2669609dfdfb895c60d78aa8adeca3 100644 --- a/include/uapi/linux/kernel-page-flags.h +++ b/include/uapi/linux/kernel-page-flags.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _UAPILINUX_KERNEL_PAGE_FLAGS_H #define _UAPILINUX_KERNEL_PAGE_FLAGS_H diff --git a/include/uapi/linux/msdos_fs.h b/include/uapi/linux/msdos_fs.h index e956704f5fb1b24ceba1b0157c8d37cf87ee3d15..5bd6dec4ff13218ca0beee44be4e733025293fd0 100644 --- a/include/uapi/linux/msdos_fs.h +++ b/include/uapi/linux/msdos_fs.h @@ -45,6 +45,7 @@ #define CASE_LOWER_BASE 8 /* base is lower case */ #define CASE_LOWER_EXT 16 /* extension is lower case */ +#define FAT_NO_83NAME 32 /* no 8.3 short filename for this file */ #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ #define IS_FREE(n) (!*(n) || *(n) == DELETED_FLAG) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 4d0b992d0ba626328a29c3e7109203dc35c12e98..cbd6731aff437abe60e85bd6ca77851a4b2f284b 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -16,82 +16,61 @@ #define IPA_IOC_MAGIC 0xCF /** - * IPA device full path - */ -#define IPA_DEV_NAME "/dev/ipa" - -/** - * IPA NAT table character device name - */ -#define IPA_NAT_DEV_NAME "ipaNatTable" - -/** - * IPA IPv6CT table character device name - */ -#define IPA_IPV6CT_DEV_NAME "ipaIpv6CTTable" - - /** * name of the default routing tables for v4 and v6 */ #define IPA_DFLT_RT_TBL_NAME "ipa_dflt_rt" /** - * commands supported by IPA driver - */ -#define IPA_IOCTL_ADD_HDR 0 -#define IPA_IOCTL_DEL_HDR 1 -#define IPA_IOCTL_ADD_RT_RULE 2 -#define IPA_IOCTL_DEL_RT_RULE 3 -#define IPA_IOCTL_ADD_FLT_RULE 4 -#define IPA_IOCTL_DEL_FLT_RULE 5 -#define IPA_IOCTL_COMMIT_HDR 6 -#define IPA_IOCTL_RESET_HDR 7 -#define IPA_IOCTL_COMMIT_RT 8 -#define IPA_IOCTL_RESET_RT 9 -#define IPA_IOCTL_COMMIT_FLT 10 -#define IPA_IOCTL_RESET_FLT 11 -#define IPA_IOCTL_DUMP 12 -#define IPA_IOCTL_GET_RT_TBL 13 -#define IPA_IOCTL_PUT_RT_TBL 14 -#define IPA_IOCTL_COPY_HDR 15 -#define IPA_IOCTL_QUERY_INTF 16 -#define IPA_IOCTL_QUERY_INTF_TX_PROPS 17 -#define IPA_IOCTL_QUERY_INTF_RX_PROPS 18 -#define IPA_IOCTL_GET_HDR 19 -#define IPA_IOCTL_PUT_HDR 20 -#define IPA_IOCTL_SET_FLT 21 -#define IPA_IOCTL_ALLOC_NAT_MEM 22 -#define IPA_IOCTL_V4_INIT_NAT 23 -#define IPA_IOCTL_TABLE_DMA_CMD 24 -#define IPA_IOCTL_NAT_DMA IPA_IOCTL_TABLE_DMA_CMD -#define IPA_IOCTL_INIT_IPV6CT_TABLE 25 -#define IPA_IOCTL_V4_DEL_NAT 26 -#define IPA_IOCTL_PULL_MSG 27 -#define IPA_IOCTL_GET_NAT_OFFSET 28 -#define IPA_IOCTL_RM_ADD_DEPENDENCY 29 -#define IPA_IOCTL_RM_DEL_DEPENDENCY 30 -#define IPA_IOCTL_GENERATE_FLT_EQ 31 -#define IPA_IOCTL_QUERY_INTF_EXT_PROPS 32 -#define IPA_IOCTL_QUERY_EP_MAPPING 33 -#define IPA_IOCTL_QUERY_RT_TBL_INDEX 34 -#define IPA_IOCTL_WRITE_QMAPID 35 -#define IPA_IOCTL_MDFY_FLT_RULE 36 -#define IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_ADD 37 -#define IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_DEL 38 -#define IPA_IOCTL_NOTIFY_WAN_EMBMS_CONNECTED 39 -#define IPA_IOCTL_ADD_HDR_PROC_CTX 40 -#define IPA_IOCTL_DEL_HDR_PROC_CTX 41 -#define IPA_IOCTL_MDFY_RT_RULE 42 -#define IPA_IOCTL_ADD_RT_RULE_AFTER 43 -#define IPA_IOCTL_ADD_FLT_RULE_AFTER 44 -#define IPA_IOCTL_GET_HW_VERSION 45 -#define IPA_IOCTL_ADD_RT_RULE_EXT 46 -#define IPA_IOCTL_NAT_MODIFY_PDN 47 -#define IPA_IOCTL_ALLOC_NAT_TABLE 48 -#define IPA_IOCTL_ALLOC_IPV6CT_TABLE 49 -#define IPA_IOCTL_DEL_NAT_TABLE 50 -#define IPA_IOCTL_DEL_IPV6CT_TABLE 51 -#define IPA_IOCTL_MAX 52 + * the commands supported by IPA driver + */ +#define IPA_IOCTL_ADD_HDR 0 +#define IPA_IOCTL_DEL_HDR 1 +#define IPA_IOCTL_ADD_RT_RULE 2 +#define IPA_IOCTL_DEL_RT_RULE 3 +#define IPA_IOCTL_ADD_FLT_RULE 4 +#define IPA_IOCTL_DEL_FLT_RULE 5 +#define IPA_IOCTL_COMMIT_HDR 6 +#define IPA_IOCTL_RESET_HDR 7 +#define IPA_IOCTL_COMMIT_RT 8 +#define IPA_IOCTL_RESET_RT 9 +#define IPA_IOCTL_COMMIT_FLT 10 +#define IPA_IOCTL_RESET_FLT 11 +#define IPA_IOCTL_DUMP 12 +#define IPA_IOCTL_GET_RT_TBL 13 +#define IPA_IOCTL_PUT_RT_TBL 14 +#define IPA_IOCTL_COPY_HDR 15 +#define IPA_IOCTL_QUERY_INTF 16 +#define IPA_IOCTL_QUERY_INTF_TX_PROPS 17 +#define IPA_IOCTL_QUERY_INTF_RX_PROPS 18 +#define IPA_IOCTL_GET_HDR 19 +#define IPA_IOCTL_PUT_HDR 20 +#define IPA_IOCTL_SET_FLT 21 +#define IPA_IOCTL_ALLOC_NAT_MEM 22 +#define IPA_IOCTL_V4_INIT_NAT 23 +#define IPA_IOCTL_NAT_DMA 24 +#define IPA_IOCTL_V4_DEL_NAT 26 +#define IPA_IOCTL_PULL_MSG 27 +#define IPA_IOCTL_GET_NAT_OFFSET 28 +#define IPA_IOCTL_RM_ADD_DEPENDENCY 29 +#define IPA_IOCTL_RM_DEL_DEPENDENCY 30 +#define IPA_IOCTL_GENERATE_FLT_EQ 31 +#define IPA_IOCTL_QUERY_INTF_EXT_PROPS 32 +#define IPA_IOCTL_QUERY_EP_MAPPING 33 +#define IPA_IOCTL_QUERY_RT_TBL_INDEX 34 +#define IPA_IOCTL_WRITE_QMAPID 35 +#define IPA_IOCTL_MDFY_FLT_RULE 36 +#define IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_ADD 37 +#define IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_DEL 38 +#define IPA_IOCTL_NOTIFY_WAN_EMBMS_CONNECTED 39 +#define IPA_IOCTL_ADD_HDR_PROC_CTX 40 +#define IPA_IOCTL_DEL_HDR_PROC_CTX 41 +#define IPA_IOCTL_MDFY_RT_RULE 42 +#define IPA_IOCTL_ADD_RT_RULE_AFTER 43 +#define IPA_IOCTL_ADD_FLT_RULE_AFTER 44 +#define IPA_IOCTL_GET_HW_VERSION 45 +#define IPA_IOCTL_ADD_RT_RULE_EXT 46 +#define IPA_IOCTL_NAT_MODIFY_PDN 47 +#define IPA_IOCTL_MAX 48 /** * max size of the header to be inserted @@ -1335,26 +1314,15 @@ struct ipa_ioc_nat_alloc_mem { }; /** - * struct ipa_ioc_nat_ipv6ct_table_alloc - NAT/IPv6CT table memory allocation - * properties - * @size: input parameter, size of table in bytes - * @offset: output parameter, offset into page in case of system memory - */ -struct ipa_ioc_nat_ipv6ct_table_alloc { - size_t size; - off_t offset; -}; - -/** - * struct ipa_ioc_v4_nat_init - nat table initialization parameters + * struct ipa_ioc_v4_nat_init - nat table initialization + * parameters * @tbl_index: input parameter, index of the table * @ipv4_rules_offset: input parameter, ipv4 rules address offset * @expn_rules_offset: input parameter, ipv4 expansion rules address offset * @index_offset: input parameter, index rules offset * @index_expn_offset: input parameter, index expansion rules offset - * @table_entries: input parameter, ipv4 rules table number of entries - * @expn_table_entries: input parameter, ipv4 expansion rules table number of - * entries + * @table_entries: input parameter, ipv4 rules table size in entries + * @expn_table_entries: input parameter, ipv4 expansion rules table size * @ip_addr: input parameter, public ip address */ struct ipa_ioc_v4_nat_init { @@ -1370,23 +1338,6 @@ struct ipa_ioc_v4_nat_init { uint32_t ip_addr; }; -/** - * struct ipa_ioc_ipv6ct_init - IPv6CT table initialization parameters - * @tbl_index: input parameter, index of the table - * @base_table_offset: input parameter, IPv6CT base table address offset - * @expn_table_offset: input parameter, IPv6CT expansion table address offset - * @table_entries: input parameter, IPv6CT table number of entries - * @expn_table_entries: input parameter, IPv6CT expansion table number of - * entries - */ -struct ipa_ioc_ipv6ct_init { - uint8_t tbl_index; - uint32_t base_table_offset; - uint32_t expn_table_offset; - uint16_t table_entries; - uint16_t expn_table_entries; -}; - /** * struct ipa_ioc_v4_nat_del - nat table delete parameter * @table_index: input parameter, index of the table @@ -1398,15 +1349,7 @@ struct ipa_ioc_v4_nat_del { }; /** - * struct ipa_ioc_nat_ipv6ct_table_del - NAT/IPv6CT table delete parameter - * @table_index: input parameter, index of the table - */ -struct ipa_ioc_nat_ipv6ct_table_del { - uint8_t table_index; -}; - -/** - * struct ipa_ioc_nat_dma_one - nat/ipv6ct dma command parameter + * struct ipa_ioc_nat_dma_one - nat dma command parameter * @table_index: input parameter, index of the table * @base_addr: type of table, from which the base address of the table * can be inferred @@ -1423,7 +1366,7 @@ struct ipa_ioc_nat_dma_one { }; /** - * struct ipa_ioc_nat_dma_cmd - To hold multiple nat/ipv6ct dma commands + * struct ipa_ioc_nat_dma_cmd - To hold multiple nat dma commands * @entries: number of dma commands in use * @dma: data pointer to the dma commands */ @@ -1434,12 +1377,12 @@ struct ipa_ioc_nat_dma_cmd { }; /** - * struct ipa_ioc_nat_pdn_entry - PDN entry modification data - * @pdn_index: index of the entry in the PDN config table to be changed - * @public_ip: PDN's public ip - * @src_metadata: PDN's source NAT metadata for metadata replacement - * @dst_metadata: PDN's destination NAT metadata for metadata replacement - */ +* struct ipa_ioc_nat_pdn_entry - PDN entry modification data +* @pdn_index: index of the entry in the PDN config table to be changed +* @public_ip: PDN's public ip +* @src_metadata: PDN's source NAT metadata for metadata replacement +* @dst_metadata: PDN's destination NAT metadata for metadata replacement +*/ struct ipa_ioc_nat_pdn_entry { uint8_t pdn_index; uint32_t public_ip; @@ -1657,33 +1600,15 @@ enum ipacm_client_enum { #define IPA_IOC_ALLOC_NAT_MEM _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ALLOC_NAT_MEM, \ struct ipa_ioc_nat_alloc_mem *) -#define IPA_IOC_ALLOC_NAT_TABLE _IOWR(IPA_IOC_MAGIC, \ - IPA_IOCTL_ALLOC_NAT_TABLE, \ - struct ipa_ioc_nat_ipv6ct_table_alloc *) -#define IPA_IOC_ALLOC_IPV6CT_TABLE _IOWR(IPA_IOC_MAGIC, \ - IPA_IOCTL_ALLOC_IPV6CT_TABLE, \ - struct ipa_ioc_nat_ipv6ct_table_alloc *) #define IPA_IOC_V4_INIT_NAT _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_V4_INIT_NAT, \ struct ipa_ioc_v4_nat_init *) -#define IPA_IOC_INIT_IPV6CT_TABLE _IOWR(IPA_IOC_MAGIC, \ - IPA_IOCTL_INIT_IPV6CT_TABLE, \ - struct ipa_ioc_ipv6ct_init *) #define IPA_IOC_NAT_DMA _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_NAT_DMA, \ struct ipa_ioc_nat_dma_cmd *) -#define IPA_IOC_TABLE_DMA_CMD _IOWR(IPA_IOC_MAGIC, \ - IPA_IOCTL_TABLE_DMA_CMD, \ - struct ipa_ioc_nat_dma_cmd *) #define IPA_IOC_V4_DEL_NAT _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_V4_DEL_NAT, \ struct ipa_ioc_v4_nat_del *) -#define IPA_IOC_DEL_NAT_TABLE _IOWR(IPA_IOC_MAGIC, \ - IPA_IOCTL_DEL_NAT_TABLE, \ - struct ipa_ioc_nat_ipv6ct_table_del *) -#define IPA_IOC_DEL_IPV6CT_TABLE _IOWR(IPA_IOC_MAGIC, \ - IPA_IOCTL_DEL_IPV6CT_TABLE, \ - struct ipa_ioc_nat_ipv6ct_table_del *) #define IPA_IOC_GET_NAT_OFFSET _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_GET_NAT_OFFSET, \ uint32_t *) diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h index 481814cb8498ea10260c37d3efb754ae76f8c846..e738d83ac01d98721260cfb8733839b23e1992c9 100644 --- a/include/uapi/linux/msm_mdp.h +++ b/include/uapi/linux/msm_mdp.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _UAPI_MSM_MDP_H_ #define _UAPI_MSM_MDP_H_ @@ -1120,7 +1125,7 @@ enum { #define MDSS_PP_SPLIT_RIGHT_ONLY 0x20000000 #define MDSS_PP_SPLIT_MASK 0x30000000 -#define MDSS_MAX_BL_BRIGHTNESS 255 +#define MDSS_MAX_BL_BRIGHTNESS 4095 #define AD_BL_LIN_LEN 256 #define AD_BL_ATT_LUT_LEN 33 diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index 61b5f8eaa7f95b8825fb0da23de99e5b4a2e766b..da9ee3bcc525a387fcc67e990aeea6f0c17d9925 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -821,26 +821,4 @@ struct mdp_hdr_stream { uint32_t content_type; uint32_t reserved[5]; }; - -/* hdr hdmi state takes possible values of 1, 2 and 4 respectively */ -#define HDR_ENABLE (1 << 0) -#define HDR_DISABLE (1 << 1) -#define HDR_RESET (1 << 2) - -/* - * HDR Control - * This encapsulates the HDR metadata as well as a state control - * for the HDR metadata as required by the HDMI spec to send the - * relevant metadata depending on the state of the HDR playback. - * hdr_state: Controls HDR state, takes values HDR_ENABLE, HDR_DISABLE - * and HDR_RESET. - * hdr_meta: Metadata sent by the userspace for the HDR clip. - */ - -#define DRM_MSM_EXT_PANEL_HDR_CTRL -struct mdp_hdr_stream_ctrl { - __u8 hdr_state; /* HDR state */ - struct mdp_hdr_stream hdr_stream; /* HDR metadata */ -}; - #endif diff --git a/include/uapi/media/msm_cam_sensor.h b/include/uapi/media/msm_cam_sensor.h index 0ec18d663cff52bfe04c0ca10c7e0a2904c1f502..28e3a239719289aadf46648806244c286a659e6e 100644 --- a/include/uapi/media/msm_cam_sensor.h +++ b/include/uapi/media/msm_cam_sensor.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __UAPI_LINUX_MSM_CAM_SENSOR_H #define __UAPI_LINUX_MSM_CAM_SENSOR_H @@ -88,7 +93,6 @@ enum sensor_sub_module_t { SUB_MODULE_EXT, SUB_MODULE_IR_LED, SUB_MODULE_IR_CUT, - SUB_MODULE_LASER_LED, SUB_MODULE_MAX, }; @@ -302,15 +306,6 @@ struct msm_ir_cut_cfg_data_t { enum msm_ir_cut_cfg_type_t cfg_type; }; -struct msm_laser_led_cfg_data_t { - enum msm_laser_led_cfg_type_t cfg_type; - void __user *setting; - void __user *debug_reg; - uint32_t debug_reg_size; - uint16_t i2c_addr; - enum i2c_freq_mode_t i2c_freq_mode; -}; - struct msm_eeprom_cfg_data { enum eeprom_cfg_type_t cfgtype; uint8_t is_supported; @@ -391,9 +386,7 @@ enum msm_ois_cfg_download_type_t { enum msm_ois_i2c_operation { MSM_OIS_WRITE = 0, MSM_OIS_POLL, - MSM_OIS_READ, }; -#define MSM_OIS_READ MSM_OIS_READ struct reg_settings_ois_t { uint16_t reg_addr; @@ -580,6 +573,16 @@ struct sensor_init_cfg_data { } cfg; }; +/* extension begin */ +#define SENSOR_EVENT_BASE (V4L2_EVENT_PRIVATE_START) +#define SENSOR_EVENT_SOF (SENSOR_EVENT_BASE + 0) + +struct msm_sensor_event_data { + uint32_t sof_count; + struct timeval mono_timestamp; +}; +/* extension end */ + #define VIDIOC_MSM_SENSOR_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct sensorb_cfg_data) @@ -628,8 +631,5 @@ struct sensor_init_cfg_data { #define VIDIOC_MSM_IR_CUT_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_ir_cut_cfg_data_t) -#define VIDIOC_MSM_LASER_LED_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_laser_led_cfg_data_t) - #endif diff --git a/include/uapi/media/msm_camera.h b/include/uapi/media/msm_camera.h index 39e6927d9b7e4e2659d3b93ded45ff0883d967a7..10ee4b7c9390f66d85d0197ad078cea4e7c3641d 100644 --- a/include/uapi/media/msm_camera.h +++ b/include/uapi/media/msm_camera.h @@ -1541,9 +1541,7 @@ enum msm_camera_i2c_reg_addr_type { MSM_CAMERA_I2C_BYTE_ADDR = 1, MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_3B_ADDR, - MSM_CAMERA_I2C_DWORD_ADDR, }; -#define MSM_CAMERA_I2C_DWORD_ADDR MSM_CAMERA_I2C_DWORD_ADDR struct msm_camera_i2c_reg_array { uint16_t reg_addr; diff --git a/include/uapi/media/msm_camsensor_sdk.h b/include/uapi/media/msm_camsensor_sdk.h index 08605aca474d5adc4cf70cb0a40050fdba50f2d9..92bb4dd4dc7131f38d48a76b9b8e3e38bbf891ff 100644 --- a/include/uapi/media/msm_camsensor_sdk.h +++ b/include/uapi/media/msm_camsensor_sdk.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __UAPI_LINUX_MSM_CAMSENSOR_SDK_H #define __UAPI_LINUX_MSM_CAMSENSOR_SDK_H @@ -85,10 +90,8 @@ enum msm_camera_i2c_reg_addr_type { MSM_CAMERA_I2C_BYTE_ADDR = 1, MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_3B_ADDR, - MSM_CAMERA_I2C_DWORD_ADDR, MSM_CAMERA_I2C_ADDR_TYPE_MAX, }; -#define MSM_CAMERA_I2C_DWORD_ADDR MSM_CAMERA_I2C_DWORD_ADDR enum msm_camera_i2c_data_type { MSM_CAMERA_I2C_BYTE_DATA = 1, @@ -115,10 +118,8 @@ enum msm_sensor_power_seq_gpio_t { SENSOR_GPIO_FL_RESET, SENSOR_GPIO_CUSTOM1, SENSOR_GPIO_CUSTOM2, - SENSOR_GPIO_CUSTOM3, SENSOR_GPIO_MAX, }; -#define SENSOR_GPIO_CUSTOM3 SENSOR_GPIO_CUSTOM3 enum msm_ir_cut_filter_gpio_t { IR_CUT_FILTER_GPIO_P = 0, @@ -208,13 +209,6 @@ enum msm_ir_led_cfg_type_t { #define CFG_IR_LED_OFF CFG_IR_LED_OFF #define CFG_IR_LED_ON CFG_IR_LED_ON -enum msm_laser_led_cfg_type_t { - CFG_LASER_LED_INIT, - CFG_LASER_LED_CONTROL, -}; -#define CFG_LASER_LED_INIT CFG_LASER_LED_INIT -#define CFG_LASER_LED_CONTROL CFG_LASER_LED_CONTROL - enum msm_ir_cut_cfg_type_t { CFG_IR_CUT_INIT = 0, CFG_IR_CUT_RELEASE, @@ -376,6 +370,9 @@ struct msm_camera_i2c_seq_reg_array { }; struct msm_camera_i2c_seq_reg_setting { +/* extension begin */ + unsigned short slave_addr; +/* extension end */ struct msm_camera_i2c_seq_reg_array *reg_setting; unsigned short size; enum msm_camera_i2c_reg_addr_type addr_type; diff --git a/include/uapi/media/msmb_camera.h b/include/uapi/media/msmb_camera.h index 4b23806071d4bbc15d58a02ae4286ba464bbd65a..df9807e72e47719a85b66d364226cf451d85a8ef 100644 --- a/include/uapi/media/msmb_camera.h +++ b/include/uapi/media/msmb_camera.h @@ -52,7 +52,6 @@ #define MSM_CAMERA_SUBDEV_IR_CUT 18 #define MSM_CAMERA_SUBDEV_EXT 19 #define MSM_CAMERA_SUBDEV_TOF 20 -#define MSM_CAMERA_SUBDEV_LASER_LED 21 #define MSM_MAX_CAMERA_SENSORS 5 /* The below macro is defined to put an upper limit on maximum diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h index 56b2f4616aa44782841855bad87bd12796ae73c1..028309d9df4ef207752c777eb1fdce39b9a7cde4 100644 --- a/include/uapi/scsi/ufs/ioctl.h +++ b/include/uapi/scsi/ufs/ioctl.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef UAPI_UFS_IOCTL_H_ #define UAPI_UFS_IOCTL_H_ @@ -8,6 +13,7 @@ * SCSI_IOCTL_GET_PCI */ #define UFS_IOCTL_QUERY 0x5388 +#define UFS_IOCTL_WRITE_BUFFER 0x53EF /** * struct ufs_ioctl_query_data - used to transfer data to and from user via ioctl @@ -54,4 +60,9 @@ struct ufs_ioctl_query_data { __u8 buffer[0]; }; +struct ufs_ioctl_write_buffer_data { + __u32 buf_size; + __u8 buffer[0]; +}; + #endif /* UAPI_UFS_IOCTL_H_ */ diff --git a/include/uapi/scsi/ufs/ufs.h b/include/uapi/scsi/ufs/ufs.h index cd82b760bd92cbaec15f4182d71b180fe936a7d7..59ea205d3b9f7e9661362d204c39e64d56af1bf9 100644 --- a/include/uapi/scsi/ufs/ufs.h +++ b/include/uapi/scsi/ufs/ufs.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef UAPI_UFS_H_ #define UAPI_UFS_H_ @@ -36,6 +41,7 @@ enum attr_idn { QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F, QUERY_ATTR_IDN_CNTX_CONF = 0x10, QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11, + QUERY_ATTR_IDN_FFU_STATUS = 0x14, }; #define QUERY_ATTR_IDN_BOOT_LU_EN_MAX 0x02 @@ -51,7 +57,7 @@ enum desc_idn { QUERY_DESC_IDN_RFU_1 = 0x6, QUERY_DESC_IDN_GEOMETRY = 0x7, QUERY_DESC_IDN_POWER = 0x8, - QUERY_DESC_IDN_RFU_2 = 0x9, + QUERY_DESC_IDN_DEVICE_HEALTH = 0x9, QUERY_DESC_IDN_MAX, }; @@ -68,4 +74,22 @@ enum query_opcode { UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, UPIU_QUERY_OPCODE_MAX, }; + +enum purge_status { + PURGE_STATUS_IDLE = 0x00, + PURGE_STATUS_IN_PROGRESS = 0x01, + PURGE_STATUS_STOPPED = 0x02, + PURGE_STATUS_COMPLETED = 0x03, + PURGE_STATUS_BUSY = 0x04, + PURGE_STATUS_GENERAL_ERROR = 0x05, +}; + +enum ffu_status { + FFU_STATUS_NO_INFOMATION = 0x00, + FFU_STATUS_SUCCESS = 0x01, + FFU_STATUS_CORRUPTION_ERROR = 0x02, + FFU_STATUS_INTERNAL_ERROR = 0x03, + FFU_STATUS_VERSION_MISMATCH = 0x04, + FFU_STATUS_GENERAL_ERROR = 0xFF, +}; #endif /* UAPI_UFS_H_ */ diff --git a/include/uapi/sound/Kbuild b/include/uapi/sound/Kbuild index a19a02471367008150b5efe05194e8a61f60d64a..42083b6f7b8d65bcb8e1f58ce9fdfda82b687e31 100644 --- a/include/uapi/sound/Kbuild +++ b/include/uapi/sound/Kbuild @@ -19,3 +19,5 @@ header-y += voice_svc.h header-y += devdep_params.h header-y += msmcal-hwdep.h header-y += wcd-dsp-glink.h +header-y += sony-hweffect.h +header-y += sony-hweffect-params.h diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 7845fdd556fa74f7de137cb5ab1331a1d0a5f4d9..866ec3d2af69ad8511cf6215549aa8c072bee7b9 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -138,11 +138,6 @@ struct snd_compr_audio_info { #define SNDRV_COMPRESS_CLK_REC_MODE_NONE 0 #define SNDRV_COMPRESS_CLK_REC_MODE_AUTO 1 -enum sndrv_compress_latency_mode { - SNDRV_COMPRESS_LEGACY_LATENCY_MODE = 0, - SNDRV_COMPRESS_LOW_LATENCY_MODE = 1, -}; - /** * enum sndrv_compress_encoder * @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the @@ -169,7 +164,6 @@ enum sndrv_compress_encoder { SNDRV_COMPRESS_START_DELAY = 9, SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK = 10, SNDRV_COMPRESS_ADJUST_SESSION_CLOCK = 11, - SNDRV_COMPRESS_LATENCY_MODE = 12, }; #define SNDRV_COMPRESS_PATH_DELAY SNDRV_COMPRESS_PATH_DELAY @@ -180,7 +174,6 @@ enum sndrv_compress_encoder { #define SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK \ SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK #define SNDRV_COMPRESS_ADJUST_SESSION_CLOCK SNDRV_COMPRESS_ADJUST_SESSION_CLOCK -#define SNDRV_COMPRESS_LATENCY_MODE SNDRV_COMPRESS_LATENCY_MODE /** * struct snd_compr_metadata - compressed stream metadata diff --git a/include/uapi/sound/devdep_params.h b/include/uapi/sound/devdep_params.h index 9e3133b76c6840c60fcec886f5cad38f3bdf643b..5061ec0da35650749d73d9a13c983f7fe5de0749 100644 --- a/include/uapi/sound/devdep_params.h +++ b/include/uapi/sound/devdep_params.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015,2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -66,14 +66,4 @@ struct dts_eagle_param_desc { uint32_t device; } __packed; -#define HWDEP_FE_BASE 3000 /*unique base for FE hw dep nodes*/ -struct snd_pcm_mmap_fd { - int32_t dir; - int32_t fd; - int32_t size; - int32_t actual_size; -}; - -#define SNDRV_PCM_IOCTL_MMAP_DATA_FD _IOWR('U', 0xd2, struct snd_pcm_mmap_fd) - #endif diff --git a/include/uapi/sound/sony-hweffect-params.h b/include/uapi/sound/sony-hweffect-params.h new file mode 100644 index 0000000000000000000000000000000000000000..57768ea18546276a05d610bef8d789370c6ce76a --- /dev/null +++ b/include/uapi/sound/sony-hweffect-params.h @@ -0,0 +1,64 @@ +/* + * Author: Yoshio Yamamoto yoshio.xa.yamamoto@sonymobile.com + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef __SONY_HWEFFECT_PARAMS_H +#define __SONY_HWEFFECT_PARAMS_H + +#define SONYEFFECT_HW_PARAMS_IOCTL_MAGIC 't' + +#define SFORCE_PARAM \ + _IOW(SONYEFFECT_HW_PARAMS_IOCTL_MAGIC, 0, unsigned) + +#define CLEARPHASE_HP_PARAM \ + _IOW(SONYEFFECT_HW_PARAMS_IOCTL_MAGIC, 1, unsigned) + +#define CLEARPHASE_SP_PARAM \ + _IOW(SONYEFFECT_HW_PARAMS_IOCTL_MAGIC, 2, unsigned) + +#define XLOUD_PARAM \ + _IOW(SONYEFFECT_HW_PARAMS_IOCTL_MAGIC, 3, unsigned) + +#define SFORCE_PARAM_SIZE 1016 +#define CLEARPHASE_HP_PARAM_SIZE 2064 +#define CLEARPHASE_SP_PARAM_SIZE 2360 +#define XLOUD_PARAM_SIZE 512 + +enum { + SFORCE_TYPE_MUSIC = 0, + SFORCE_TYPE_VIDEO, + SFORCE_TYPE_MAX +}; + +struct sforce_param_data { + unsigned char data[SFORCE_PARAM_SIZE]; +}; + +struct clearphase_hp_param_data { + unsigned char data[CLEARPHASE_HP_PARAM_SIZE]; +}; + +struct clearphase_sp_param_data { + unsigned char data[CLEARPHASE_SP_PARAM_SIZE]; +}; + +struct xloud_param_data { + unsigned int level; + unsigned char data[XLOUD_PARAM_SIZE]; +}; + +void *sony_hweffect_params_getparam(unsigned int effect_id); + +#endif diff --git a/include/uapi/sound/sony-hweffect.h b/include/uapi/sound/sony-hweffect.h new file mode 100644 index 0000000000000000000000000000000000000000..f09b40cc747b9c783975c96bfff778a0b25d7c03 --- /dev/null +++ b/include/uapi/sound/sony-hweffect.h @@ -0,0 +1,177 @@ +/* + * Author: Yoshio Yamamoto yoshio.xa.yamamoto@sonymobile.com + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef _SONY_HWEFFECT_H +#define _SONY_HWEFFECT_H + +/** SONY HW EFFECT **/ + +/* CONFIG GET/SET */ +#define CONFIG_CACHE 0 +#define CONFIG_SET 1 +#define CONFIG_GET 2 + +/* CONFIG HEADER */ +/* + + MODULE_ID, + DEVICE, + NUM_COMMANDS, + COMMAND_ID_1, + CONFIG_CACHE/SET/GET, + OFFSET_1, + LENGTH_1, + VALUES_1, + ..., + ..., + COMMAND_ID_2, + CONFIG_CACHE/SET/GET, + OFFSET_2, + LENGTH_2, + VALUES_2, + ..., + ..., + COMMAND_ID_3, + ... +*/ + +#define BAND_NUM 6 + +/* CONFIG PARAM IDs */ +#define SONYBUNDLE_MODULE 0x00011000 + +#define SONYBUNDLE_ENABLE 0x00011001 + +#define DYNAMIC_NORMALIZER_ENABLE 0x00011011 + +#define SFORCE_ENABLE 0x00011021 +#define SFORCE_PARAM_TYPE 0x00011022 + +#define VPT20_MODE 0x00011031 + +#define CLEARPHASE_HP_MODE 0x00011041 + +#define CLEARAUDIO_CHSEP 0x00011051 +#define CLEARAUDIO_EQ_COEF 0x00011052 +#define CLEARAUDIO_VOLUME 0x00011053 + +#define CLEARPHASE_SP_ENABLE 0x00011061 + +#define XLOUD_ENABLE 0x00011071 + +#define DOWN_CONVERT 0x00011081 + +#define SONYBUNDLE_ENABLE_PARAM_LEN 1 +#define DYNAMIC_NORMALIZER_ENABLE_PARAM_LEN 1 +#define SFORCE_ENABLE_PARAM_LEN 1 +#define VPT20_MODE_PARAM_LEN 1 +#define CLEARPHASE_HP_MODE_PARAM_LEN 1 +#define CLEARAUDIO_CHSEP_PARAM_LEN 1 +#define CLEARAUDIO_EQ_COEF_PARAM_LEN 6 +#define CLEARAUDIO_VOLUME_PARAM_LEN 1 +#define CLEARPHASE_SP_ENABLE_PARAM_LEN 1 +#define XLOUD_ENABLE_PARAM_LEN 1 +#define DOWN_CONVERT_PARAM_LEN 1 + +#define COMMAND_PAYLOAD_LEN 3 +#define COMMAND_PAYLOAD_SZ (COMMAND_PAYLOAD_LEN * sizeof(uint32_t)) +#define MAX_INBAND_PARAM_SZ 4096 + +#define SONYBUNDLE_ENABLE_PARAM_SZ \ + (SONYBUNDLE_ENABLE_PARAM_LEN*sizeof(uint32_t)) +#define DYNAMIC_NORMALIZER_ENABLE_PARAM_SZ \ + (DYNAMIC_NORMALIZER_ENABLE_PARAM_LEN*sizeof(uint32_t)) +#define SFORCE_ENABLE_PARAM_SZ \ + (SFORCE_ENABLE_PARAM_LEN*sizeof(uint32_t)) +#define VPT20_MODE_PARAM_SZ \ + (VPT20_MODE_PARAM_LEN*sizeof(uint32_t)) +#define CLEARPHASE_HP_MODE_PARAM_SZ \ + (CLEARPHASE_HP_MODE_PARAM_LEN*sizeof(uint32_t)) +#define CLEARAUDIO_CHSEP_PARAM_SZ \ + (CLEARAUDIO_CHSEP_PARAM_LEN*sizeof(uint32_t)) +#define CLEARAUDIO_EQ_COEF_PARAM_SZ \ + (CLEARAUDIO_EQ_COEF_PARAM_LEN*sizeof(int16_t)) +#define CLEARAUDIO_VOLUME_PARAM_SZ \ + (CLEARAUDIO_VOLUME_PARAM_LEN*sizeof(int32_t)) +#define CLEARPHASE_SP_ENABLE_PARAM_SZ \ + (CLEARPHASE_SP_ENABLE_PARAM_LEN*sizeof(uint32_t)) +#define XLOUD_ENABLE_PARAM_SZ \ + (XLOUD_ENABLE_PARAM_LEN*sizeof(uint32_t)) +#define DOWN_CONVERT_PARAM_SZ \ + (DOWN_CONVERT_PARAM_LEN*sizeof(uint32_t)) + +struct common_params { + uint16_t enable_flag; + uint16_t reserved; +}; + +struct dynamic_normalizer_params { + uint16_t enable_flag; + uint16_t reserved; +}; + +struct sforce_params { + uint16_t enable_flag; + uint16_t reserved; +}; + +struct vpt20_params { + uint16_t mode; + uint16_t reserved; +}; + +struct clearphase_hp_params { + uint16_t mode; + uint16_t reserved; +}; + +struct clearaudio_params { + int32_t chsep_coef; + int16_t eq_coef[6]; +}; + +struct clearaudio_volume { + uint16_t gain; + uint16_t reserved; +}; + +struct clearphase_sp_params { + uint16_t mode; + uint16_t reserved; +}; + +struct xloud_params { + uint16_t enable_flag; + uint16_t reserved; +}; + +struct sonybundle_params { + struct common_params common; + struct dynamic_normalizer_params dynamic_normalizer; + struct sforce_params sforce; + bool sforce_tuning_update; + struct vpt20_params vpt20; + struct clearphase_hp_params clearphase_hp; + struct clearaudio_params clearaudio; + struct clearaudio_volume ca_volume; + struct clearphase_sp_params clearphase_sp; + bool clearphase_sp_tuning_update; + struct xloud_params xloud; + bool xloud_tuning_update; + uint16_t down_convert_enable; +}; + +#endif /*_SONYEFFECT_HW_H */ diff --git a/init/initramfs.c b/init/initramfs.c index f8ce812ba43e9356fdf35393d6c6b423078514ba..1984855f3a3a754e2034a8aaae5133c01656353f 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -3,6 +3,11 @@ * to be __user pointers not __kernel pointers. To limit the sparse * noise, turn off sparse checking for this file. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifdef __CHECKER__ #undef __CHECKER__ #warning "Sparse checking disabled for this file" @@ -633,6 +638,8 @@ static int __init populate_rootfs(void) printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n"); err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start); + if (err) + panic("panic in %s()", __func__); if (!err) { free_initrd(); goto done; diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 46436543ad28a221629bede8a69dcc8486febfc6..25b7a678f9efa0336b665b6af0fe236bc46043d1 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1251,10 +1251,8 @@ retry: timeo = MAX_SCHEDULE_TIMEOUT; ret = netlink_attachskb(sock, nc, &timeo, NULL); - if (ret == 1) { - sock = NULL; + if (ret == 1) goto retry; - } if (ret) { sock = NULL; nc = NULL; diff --git a/kernel/Makefile b/kernel/Makefile index 53abf008ecb39758e1812f7a593323d65e7fd304..32b9af699a629b6080c31af001656b1b80b259dd 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_TORTURE_TEST) += torture.o obj-$(CONFIG_MEMBARRIER) += membarrier.o obj-$(CONFIG_HAS_IOMEM) += memremap.o +obj-$(CONFIG_CRASH_NOTES) += crash_notes.o $(obj)/configs.o: $(obj)/config_data.h diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c97bce6a0e0e9e10aad68465f6eed759908b4eb4..85de5094b936db002df38dac41a3e14a15e8730f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -765,11 +765,6 @@ static int check_xadd(struct verifier_env *env, struct bpf_insn *insn) if (err) return err; - if (is_pointer_value(env, insn->src_reg)) { - verbose("R%d leaks addr into mem\n", insn->src_reg); - return -EACCES; - } - /* check whether atomic_add can read the memory */ err = check_mem_access(env, insn->dst_reg, insn->off, BPF_SIZE(insn->code), BPF_READ, -1); diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 3fdb7545852e96ca6f835f741f711cda3fc85cac..077bb52e2d478c4e3dc89e850a5861dc2d937d6e 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2799,7 +2799,6 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk) int retval = 0; mutex_lock(&cgroup_mutex); - percpu_down_write(&cgroup_threadgroup_rwsem); for_each_root(root) { struct cgroup *from_cgrp; @@ -2814,7 +2813,6 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk) if (retval) break; } - percpu_up_write(&cgroup_threadgroup_rwsem); mutex_unlock(&cgroup_mutex); return retval; @@ -4074,8 +4072,6 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from) mutex_lock(&cgroup_mutex); - percpu_down_write(&cgroup_threadgroup_rwsem); - /* all tasks in @from are being moved, all csets are source */ spin_lock_irq(&css_set_lock); list_for_each_entry(link, &from->cset_links, cset_link) @@ -4104,7 +4100,6 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from) } while (task && !ret); out_err: cgroup_migrate_finish(&preloaded_csets); - percpu_up_write(&cgroup_threadgroup_rwsem); mutex_unlock(&cgroup_mutex); return ret; } diff --git a/kernel/cpu.c b/kernel/cpu.c index 5b4440d57f89ff24923d4352c380c58e8d228f24..1a26ef5b7d58c7b82d768737df4e3e8449a0e344 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -91,11 +91,6 @@ static struct { #define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map) #define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map) -void cpu_hotplug_mutex_held(void) -{ - lockdep_assert_held(&cpu_hotplug.lock); -} -EXPORT_SYMBOL(cpu_hotplug_mutex_held); void get_online_cpus(void) { @@ -380,21 +375,6 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen) goto out_release; } - /* - * By now we've cleared cpu_active_mask, wait for all preempt-disabled - * and RCU users of this state to go away such that all new such users - * will observe it. - * - * For CONFIG_PREEMPT we have preemptible RCU and its sync_rcu() might - * not imply sync_sched(), so wait for both. - * - * Do sync before park smpboot threads to take care the rcu boost case. - */ - if (IS_ENABLED(CONFIG_PREEMPT)) - synchronize_rcu_mult(call_rcu, call_rcu_sched); - else - synchronize_rcu(); - smpboot_park_threads(cpu); /* @@ -528,8 +508,8 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen) ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls); if (ret) { nr_calls--; - pr_warn_ratelimited("%s: attempt to bring up CPU %u failed\n", - __func__, cpu); + pr_warn("%s: attempt to bring up CPU %u failed\n", + __func__, cpu); goto out_notify; } diff --git a/kernel/cpuset.c b/kernel/cpuset.c index a210812019296bddd80cbee9378fda6089b407df..03dbc231a4a058fe79c1b47c4a5fa244f825fc8b 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -806,15 +806,16 @@ done: * 'cpus' is removed, then call this routine to rebuild the * scheduler's dynamic sched domains. * + * Call with cpuset_mutex held. Takes get_online_cpus(). */ -static void rebuild_sched_domains_unlocked(void) +static void rebuild_sched_domains_locked(void) { struct sched_domain_attr *attr; cpumask_var_t *doms; int ndoms; - cpu_hotplug_mutex_held(); lockdep_assert_held(&cpuset_mutex); + get_online_cpus(); /* * We have raced with CPU hotplug. Don't do anything to avoid @@ -822,27 +823,27 @@ static void rebuild_sched_domains_unlocked(void) * Anyways, hotplug work item will rebuild sched domains. */ if (!cpumask_equal(top_cpuset.effective_cpus, cpu_active_mask)) - return; + goto out; /* Generate domain masks and attrs */ ndoms = generate_sched_domains(&doms, &attr); /* Have scheduler rebuild the domains */ partition_sched_domains(ndoms, doms, attr); +out: + put_online_cpus(); } #else /* !CONFIG_SMP */ -static void rebuild_sched_domains_unlocked(void) +static void rebuild_sched_domains_locked(void) { } #endif /* CONFIG_SMP */ void rebuild_sched_domains(void) { - get_online_cpus(); mutex_lock(&cpuset_mutex); - rebuild_sched_domains_unlocked(); + rebuild_sched_domains_locked(); mutex_unlock(&cpuset_mutex); - put_online_cpus(); } /** @@ -874,6 +875,7 @@ static void update_tasks_cpumask(struct cpuset *cs) * * On legacy hierachy, effective_cpus will be the same with cpu_allowed. * + * Called with cpuset_mutex held */ static void update_cpumasks_hier(struct cpuset *cs, struct cpumask *new_cpus) { @@ -928,7 +930,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct cpumask *new_cpus) rcu_read_unlock(); if (need_rebuild_sched_domains) - rebuild_sched_domains_unlocked(); + rebuild_sched_domains_locked(); } /** @@ -1287,7 +1289,7 @@ static int update_relax_domain_level(struct cpuset *cs, s64 val) cs->relax_domain_level = val; if (!cpumask_empty(cs->cpus_allowed) && is_sched_load_balance(cs)) - rebuild_sched_domains_unlocked(); + rebuild_sched_domains_locked(); } return 0; @@ -1318,6 +1320,7 @@ static void update_tasks_flags(struct cpuset *cs) * cs: the cpuset to update * turning_on: whether the flag is being set or cleared * + * Call with cpuset_mutex held. */ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, @@ -1352,7 +1355,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, spin_unlock_irq(&callback_lock); if (!cpumask_empty(trialcs->cpus_allowed) && balance_flag_changed) - rebuild_sched_domains_unlocked(); + rebuild_sched_domains_locked(); if (spread_flag_changed) update_tasks_flags(cs); @@ -1617,7 +1620,6 @@ static int cpuset_write_u64(struct cgroup_subsys_state *css, struct cftype *cft, cpuset_filetype_t type = cft->private; int retval = 0; - get_online_cpus(); mutex_lock(&cpuset_mutex); if (!is_cpuset_online(cs)) { retval = -ENODEV; @@ -1655,7 +1657,6 @@ static int cpuset_write_u64(struct cgroup_subsys_state *css, struct cftype *cft, } out_unlock: mutex_unlock(&cpuset_mutex); - put_online_cpus(); return retval; } @@ -1666,7 +1667,6 @@ static int cpuset_write_s64(struct cgroup_subsys_state *css, struct cftype *cft, cpuset_filetype_t type = cft->private; int retval = -ENODEV; - get_online_cpus(); mutex_lock(&cpuset_mutex); if (!is_cpuset_online(cs)) goto out_unlock; @@ -1681,7 +1681,6 @@ static int cpuset_write_s64(struct cgroup_subsys_state *css, struct cftype *cft, } out_unlock: mutex_unlock(&cpuset_mutex); - put_online_cpus(); return retval; } @@ -1720,7 +1719,6 @@ static ssize_t cpuset_write_resmask(struct kernfs_open_file *of, kernfs_break_active_protection(of->kn); flush_work(&cpuset_hotplug_work); - get_online_cpus(); mutex_lock(&cpuset_mutex); if (!is_cpuset_online(cs)) goto out_unlock; @@ -1746,7 +1744,6 @@ static ssize_t cpuset_write_resmask(struct kernfs_open_file *of, free_trial_cpuset(trialcs); out_unlock: mutex_unlock(&cpuset_mutex); - put_online_cpus(); kernfs_unbreak_active_protection(of->kn); css_put(&cs->css); flush_workqueue(cpuset_migrate_mm_wq); @@ -2052,14 +2049,13 @@ out_unlock: /* * If the cpuset being removed has its flag 'sched_load_balance' * enabled, then simulate turning sched_load_balance off, which - * will call rebuild_sched_domains_unlocked(). + * will call rebuild_sched_domains_locked(). */ static void cpuset_css_offline(struct cgroup_subsys_state *css) { struct cpuset *cs = css_cs(css); - get_online_cpus(); mutex_lock(&cpuset_mutex); if (is_sched_load_balance(cs)) @@ -2069,7 +2065,6 @@ static void cpuset_css_offline(struct cgroup_subsys_state *css) clear_bit(CS_ONLINE, &cs->flags); mutex_unlock(&cpuset_mutex); - put_online_cpus(); } static void cpuset_css_free(struct cgroup_subsys_state *css) diff --git a/kernel/crash_notes.c b/kernel/crash_notes.c new file mode 100644 index 0000000000000000000000000000000000000000..a8c1206ee05fd8c975bfe5eb2fa9947f91f5725c --- /dev/null +++ b/kernel/crash_notes.c @@ -0,0 +1,187 @@ +/* kernel/crash_notes.c + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CRASH_NOTE_NAME "CORE" + +#define CRASH_NOTE_SIZE (ALIGN(sizeof(struct elf_note), 4) + \ + ALIGN(sizeof(CRASH_NOTE_NAME), 4) + \ + ALIGN(sizeof(struct elf_prstatus), 4)) + +#define CRASH_NOTE_BYTES (2 * CRASH_NOTE_SIZE) + +typedef u32 note_buf_t[CRASH_NOTE_BYTES / 4]; +note_buf_t *crash_notes; + +static atomic_t crash_notes_ipi; + +static inline void crash_notes_save_this_cpu(enum crash_note_save_type type, + unsigned int cpu) +{ + struct elf_prstatus prstatus; + struct pt_regs regs; + struct elf_note *note; + u32 *buf; + u32 *start; + + buf = (u32 *)per_cpu_ptr(crash_notes, cpu); + if (!buf) + return; + + start = buf; + memset(&prstatus, 0, sizeof(prstatus)); + prstatus.pr_pid = current->pid; + + if (type != CRASH_NOTE_INIT) { + crash_notes_save_regs(®s); + elf_core_copy_regs(&prstatus.pr_reg, ®s); + } + + note = (struct elf_note *)buf; + note->n_namesz = strnlen(CRASH_NOTE_NAME, 5) + 1; + note->n_descsz = sizeof(prstatus); + note->n_type = NT_PRSTATUS; + buf += (sizeof(struct elf_note) + 3) / 4; + memcpy(buf, CRASH_NOTE_NAME, note->n_namesz); + buf += (note->n_namesz + 3) / 4; + memcpy(buf, &prstatus, sizeof(prstatus)); + buf += (note->n_descsz + 3) / 4; + + note = (struct elf_note *)buf; + note->n_namesz = 0; + note->n_descsz = 0; + note->n_type = 0; + + flush_cache_all(); +} + +static DEFINE_RAW_SPINLOCK(print_trace_lock); + +static void crash_notes_save_nopanic_cpu(void *unused) +{ + unsigned int cpu = smp_processor_id(); + + raw_spin_lock(&print_trace_lock); + pr_crit("CPU%u: stopping\n", cpu); + dump_stack(); + raw_spin_unlock(&print_trace_lock); + + crash_notes_save_this_cpu(CRASH_NOTE_STOPPING, cpu); + atomic_dec(&crash_notes_ipi); + + set_cpu_active(cpu, false); + flush_cache_all(); + + while (1) + cpu_relax(); +} + +void crash_notes_save_cpus(void) +{ + unsigned long msecs; + + local_irq_disable(); + + atomic_set(&crash_notes_ipi, num_online_cpus() - 1); + smp_call_function(crash_notes_save_nopanic_cpu, NULL, false); + msecs = 1000; + while ((atomic_read(&crash_notes_ipi) > 0) && msecs) { + mdelay(1); + msecs--; + } + + if (atomic_read(&crash_notes_ipi) > 0) + pr_warn("Non-crashing CPUs did not react to IPI\n"); +} +EXPORT_SYMBOL(crash_notes_save_cpus); + +static int crash_notes_save_panic_cpu(struct notifier_block *this, + unsigned long event, void *ptr) +{ + long i; + + crash_notes_save_this_cpu(CRASH_NOTE_CRASHING, smp_processor_id()); + + bust_spinlocks(0); + + if (panic_timeout > 0) { + /* + * Delay timeout seconds before rebooting the machine. + * We can't use the "normal" timers since we just panicked. + */ + pr_emerg("Rebooting in %d seconds..", panic_timeout); + + for (i = 0; i < panic_timeout; i++) { + touch_nmi_watchdog(); + mdelay(MSEC_PER_SEC); + } + /* + * This will not be a clean reboot, with everything + * shutting down. But if there is a chance of + * rebooting the system it will be rebooted. + */ + emergency_restart(); + } + + local_irq_enable(); + while (1) { + touch_softlockup_watchdog(); + mdelay(MSEC_PER_SEC); + } + + return NOTIFY_DONE; +} + +static struct notifier_block panic_block = { + .notifier_call = crash_notes_save_panic_cpu, + .priority = INT_MIN /* will not return; must be done last */ +}; + +static int __init crash_notes_init(void) +{ + int i; + + /* Allocate memory for saving cpu registers. */ + crash_notes = alloc_percpu(note_buf_t); + if (!crash_notes) { + pr_err("allocation of percpu crash notes failed\n"); + return -ENOMEM; + } + + /* Initialize memory with something that the tools pick up on */ + /* It will NOT be useful register info, but it's something at least */ + for_each_possible_cpu(i) { + crash_notes_save_this_cpu(CRASH_NOTE_INIT, i); + } + + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); + + return 0; +} +module_init(crash_notes_init) diff --git a/kernel/events/core.c b/kernel/events/core.c index 69f8f683138ade40745a23346c02acc48ab25209..7fee87daac56da5e04207bfe304b122ac5a647f5 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1693,33 +1693,7 @@ static int __perf_remove_from_context(void *info) return 0; } - -#ifdef CONFIG_SMP -static void perf_retry_remove(struct perf_event *event, - struct remove_event *rep) -{ - int up_ret; - /* - * CPU was offline. Bring it online so we can - * gracefully exit a perf context. - */ - up_ret = cpu_up(event->cpu); - if (!up_ret) - /* Try the remove call once again. */ - cpu_function_call(event->cpu, __perf_remove_from_context, - rep); - else - pr_err("Failed to bring up CPU: %d, ret: %d\n", - event->cpu, up_ret); -} -#else -static void perf_retry_remove(struct perf_event *event, - struct remove_event *rep) -{ -} -#endif - - /* +/* * Remove the event from a task's (or a CPU's) list of events. * * CPU events are removed with a smp call. For task events we only @@ -1754,9 +1728,6 @@ static void __ref perf_remove_from_context(struct perf_event *event, */ ret = cpu_function_call(event->cpu, __perf_remove_from_context, &re); - if (ret == -ENXIO) - perf_retry_remove(event, &re); - return; } @@ -3437,27 +3408,22 @@ u64 perf_event_read_local(struct perf_event *event) static int perf_event_read(struct perf_event *event, bool group) { - int event_cpu, ret = 0; + int ret = 0; /* * If event is enabled and currently active on a CPU, update the * value in the event structure: */ - event_cpu = READ_ONCE(event->oncpu); - if (event->state == PERF_EVENT_STATE_ACTIVE && - !cpu_isolated(event_cpu)) { + !cpu_isolated(event->oncpu)) { struct perf_read_data data = { .event = event, .group = group, .ret = 0, }; - - if ((unsigned int)event_cpu >= nr_cpu_ids) - return 0; if (!event->attr.exclude_idle || - !per_cpu(is_idle, event_cpu)) { - smp_call_function_single(event_cpu, + !per_cpu(is_idle, event->oncpu)) { + smp_call_function_single(event->oncpu, __perf_event_read, &data, 1); ret = data.ret; } @@ -7143,8 +7109,6 @@ static struct pmu perf_swevent = { .start = perf_swevent_start, .stop = perf_swevent_stop, .read = perf_swevent_read, - - .events_across_hotplug = 1, }; #ifdef CONFIG_EVENT_TRACING @@ -7266,8 +7230,6 @@ static struct pmu perf_tracepoint = { .start = perf_swevent_start, .stop = perf_swevent_stop, .read = perf_swevent_read, - - .events_across_hotplug = 1, }; static inline void perf_tp_register(void) @@ -7555,8 +7517,6 @@ static struct pmu perf_cpu_clock = { .start = cpu_clock_event_start, .stop = cpu_clock_event_stop, .read = cpu_clock_event_read, - - .events_across_hotplug = 1, }; /* @@ -7638,8 +7598,6 @@ static struct pmu perf_task_clock = { .start = task_clock_event_start, .stop = task_clock_event_stop, .read = task_clock_event_read, - - .events_across_hotplug = 1, }; static void perf_pmu_nop_void(struct pmu *pmu) diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index 7da5b674d16e048fdecb13f0a7b8d09669811330..92ce5f4ccc264e01a5551965d173e39e41392143 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c @@ -614,8 +614,6 @@ static struct pmu perf_breakpoint = { .start = hw_breakpoint_start, .stop = hw_breakpoint_stop, .read = hw_breakpoint_pmu_read, - - .events_across_hotplug = 1, }; int __init init_hw_breakpoint(void) diff --git a/kernel/extable.c b/kernel/extable.c index 4f06fc34313fc4480c90199ddf3bc9b7e466b031..e820ccee984673e77b23b09ff42a0db254aba762 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -66,7 +66,7 @@ static inline int init_kernel_text(unsigned long addr) return 0; } -int notrace core_kernel_text(unsigned long addr) +int core_kernel_text(unsigned long addr) { if (addr >= (unsigned long)_stext && addr < (unsigned long)_etext) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 2c2effdb4437ac4e84db61e0ec47dc27c619a0c6..49595f877b2db1ff40206581d42cc14980d1f5bf 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -6,6 +6,11 @@ * * This file contains driver APIs to the irq subsystem. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "genirq: " fmt diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 14b9cca36b05d684d2b74f29ddbb7b5f15d3e83f..b39f049c502b24d605bd3bff360603aab8c627d7 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -17,6 +17,11 @@ * * Also see Documentation/locking/mutex-design.txt. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -26,7 +31,6 @@ #include #include #include -#include /* * In the DEBUG case we are using the "NULL fastpath" for mutexes, @@ -379,17 +383,6 @@ static bool mutex_optimistic_spin(struct mutex *lock, * values at the cost of a few extra spins. */ cpu_relax_lowlatency(); - - /* - * On arm systems, we must slow down the waiter's repeated - * aquisition of spin_mlock and atomics on the lock count, or - * we risk starving out a thread attempting to release the - * mutex. The mutex slowpath release must take spin lock - * wait_lock. This spin lock can share a monitor with the - * other waiter atomics in the mutex data structure, so must - * take care to rate limit the waiters. - */ - udelay(1); } osq_unlock(&lock->osq); diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 75c950ede9c7eee30c0b0b5be33dfa733d553bb6..a4d4de05b2d16707becf6179f8ae2ebed334bead 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -510,41 +510,6 @@ struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem) { unsigned long flags; - /* - * If a spinner is present, there is a chance that the load of - * rwsem_has_spinner() in rwsem_wake() can be reordered with - * respect to decrement of rwsem count in __up_write() leading - * to wakeup being missed. - * - * spinning writer up_write caller - * --------------- ----------------------- - * [S] osq_unlock() [L] osq - * spin_lock(wait_lock) - * sem->count=0xFFFFFFFF00000001 - * +0xFFFFFFFF00000000 - * count=sem->count - * MB - * sem->count=0xFFFFFFFE00000001 - * -0xFFFFFFFF00000001 - * RMB - * spin_trylock(wait_lock) - * return - * rwsem_try_write_lock(count) - * spin_unlock(wait_lock) - * schedule() - * - * Reordering of atomic_long_sub_return_release() in __up_write() - * and rwsem_has_spinner() in rwsem_wake() can cause missing of - * wakeup in up_write() context. In spinning writer, sem->count - * and local variable count is 0XFFFFFFFE00000001. It would result - * in rwsem_try_write_lock() failing to acquire rwsem and spinning - * writer going to sleep in rwsem_down_write_failed(). - * - * The smp_rmb() here is to make sure that the spinner state is - * consulted after sem->count is updated in up_write context. - */ - smp_rmb(); - /* * If a spinner is present, it is not necessary to do the wakeup. * Try to do wakeup only if the trylock succeeds to minimize diff --git a/kernel/panic.c b/kernel/panic.c index 75f564a94a825f9391b4cdf776bc40eb739e912c..d05bd6008202848e6de5f4241aec17674e50a0de 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -3,6 +3,11 @@ * * Copyright (C) 1991, 1992 Linus Torvalds */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * This function is used through-out the kernel (including mm and fs) @@ -24,7 +29,7 @@ #include #include #include -#include +#include #define CREATE_TRACE_POINTS #include @@ -109,7 +114,6 @@ void panic(const char *fmt, ...) va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); - dump_stack_minidump(0); pr_emerg("Kernel panic - not syncing: %s\n", buf); #ifdef CONFIG_DEBUG_BUGVERBOSE /* @@ -128,6 +132,9 @@ void panic(const char *fmt, ...) if (!crash_kexec_post_notifiers) crash_kexec(NULL); + /* Store crash context for all other no panic cpus */ + crash_notes_save_cpus(); + /* * Note smp_send_stop is the usual smp shutdown function, which * unfortunately means it may not be hardened to work in a panic @@ -174,7 +181,7 @@ void panic(const char *fmt, ...) * Delay timeout seconds before rebooting the machine. * We can't use the "normal" timers since we just panicked. */ - pr_emerg("Rebooting in %d seconds..\n", panic_timeout); + pr_emerg("Rebooting in %d seconds..", panic_timeout); for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) { touch_nmi_watchdog(); diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 6d6f63be1f9b487a6c19c3d5210c6ec703a19216..ffa118ca86a8542c4e0111d1195f868e7bb6ddaf 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -210,6 +210,18 @@ config DPM_WATCHDOG_TIMEOUT default 60 depends on DPM_WATCHDOG +config PM_WAKEUP_TIMES + bool "Log time taken for device wakeup" + def_bool y + depends on PM && PM_SLEEP && DEBUG_FS + ---help--- + This enables code that calculates the total time spent for device + suspend and resume. These statistics are then logged to + /suspend_stats. + + The statistics include minimum, maximum, average and the most recent + times for resume and suspend. + config PM_TRACE bool help @@ -321,3 +333,10 @@ config PM_GENERIC_DOMAINS_OF config CPU_PM bool + +config WAKEUP_IRQ_DEBUG + bool "Debug info of wakeup irq" + default n + ---help--- + This enables debug information about wakeup interrupts using + sysfs (/sys/kernel/). diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 22eb9ed879ade88b5f427728b07e41742aabb486..8047d31590c2daf157b1877602a983f58738f4de 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o obj-$(CONFIG_SUSPEND) += wakeup_reason.o +obj-$(CONFIG_WAKEUP_IRQ_DEBUG) += wakeup_irq_debug.o diff --git a/kernel/power/main.c b/kernel/power/main.c index 5ea50b1b7595ba778eaaf90de9c3af51586156af..667a29a530e16bf90e7ce4684e97d80d1f3de162 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -7,6 +7,11 @@ * This file is released under the GPLv2 * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -15,12 +20,48 @@ #include #include #include +#include +#ifdef CONFIG_PM_WAKEUP_TIMES +#include +#endif #include "power.h" DEFINE_MUTEX(pm_mutex); #ifdef CONFIG_PM_SLEEP +/* + * Enable/Disable suspend back off logic attribute + */ +static bool sbo_enabled = true; + +/* + * For how many percent an alive time is decayed + * if suspend back-off keeps ongoing. + */ +static u32 sbo_decay_value = 20; + +/* + * Initial max back-off alive time + */ +static u32 sbo_initial_alive_time_msecs = 10000; + +/* + * A time in milliseconds, before which a short + * sleep counter is increased to trigger a back-off. + */ +static u32 sbo_short_sleep_msecs = 1100; + +/* + * This variable regulates starting of suspend + * back off functionality, after counter is reached + * specified value. + */ +static u32 sbo_short_sleep_count = 10; + +static u32 decay_alive_time_ms; +static u32 suspend_short_count; +static struct wakeup_source *ws; /* Routines for PM-transition notifications */ @@ -215,6 +256,51 @@ static int suspend_stats_show(struct seq_file *s, void *unused) suspend_stats.failed_steps[index])); } +#ifdef CONFIG_PM_WAKEUP_TIMES + seq_printf(s, "%s\n%s %lldms (%s %lldms %s %lldms)\n" \ + "%s %lldms (%s %lldms %s %lldms)\n" \ + "%s %lldms (%s %lldms %s %lldms)\n" \ + "%s %lldms\n", + "suspend time:", + " min:", ktime_to_ms(ktime_sub( + suspend_stats.suspend_min_time.end, + suspend_stats.suspend_min_time.start)), + "start:", ktime_to_ms(suspend_stats.suspend_min_time.start), + "end:", ktime_to_ms(suspend_stats.suspend_min_time.end), + " max:", ktime_to_ms(ktime_sub( + suspend_stats.suspend_max_time.end, + suspend_stats.suspend_max_time.start)), + "start:", ktime_to_ms(suspend_stats.suspend_max_time.start), + "end:", ktime_to_ms(suspend_stats.suspend_max_time.end), + " last:", ktime_to_ms(ktime_sub( + suspend_stats.suspend_last_time.end, + suspend_stats.suspend_last_time.start)), + "start:", ktime_to_ms(suspend_stats.suspend_last_time.start), + "end:", ktime_to_ms(suspend_stats.suspend_last_time.end), + " avg:", ktime_to_ms(suspend_stats.suspend_avg_time)); + + seq_printf(s, "%s\n%s %lldms (%s %lldms %s %lldms)\n" \ + "%s %lldms (%s %lldms %s %lldms)\n" \ + "%s %lldms (%s %lldms %s %lldms)\n" \ + "%s %lldms\n", + "resume time:", + " min:", ktime_to_ms(ktime_sub( + suspend_stats.resume_min_time.end, + suspend_stats.resume_min_time.start)), + "start:", ktime_to_ms(suspend_stats.resume_min_time.start), + "end:", ktime_to_ms(suspend_stats.resume_min_time.end), + " max:", ktime_to_ms(ktime_sub( + suspend_stats.resume_max_time.end, + suspend_stats.resume_max_time.start)), + "start:", ktime_to_ms(suspend_stats.resume_max_time.start), + "end:", ktime_to_ms(suspend_stats.resume_max_time.end), + " last:", ktime_to_ms(ktime_sub( + suspend_stats.resume_last_time.end, + suspend_stats.resume_last_time.start)), + "start:", ktime_to_ms(suspend_stats.resume_last_time.start), + "end:", ktime_to_ms(suspend_stats.resume_last_time.end), + " avg:", ktime_to_ms(suspend_stats.resume_avg_time)); +#endif return 0; } @@ -223,10 +309,29 @@ static int suspend_stats_open(struct inode *inode, struct file *file) return single_open(file, suspend_stats_show, NULL); } +#ifdef CONFIG_PM_WAKEUP_TIMES +static unsigned int suspend_stats_poll(struct file *filp, + struct poll_table_struct *wait) +{ + unsigned int mask = 0; + + poll_wait(filp, &suspend_stats_queue.wait_queue, wait); + if (suspend_stats_queue.resume_done) { + mask |= (POLLIN | POLLRDNORM); + suspend_stats_queue.resume_done = 0; + } + + return mask; +} +#endif + static const struct file_operations suspend_stats_operations = { .open = suspend_stats_open, .read = seq_read, .llseek = seq_lseek, +#ifdef CONFIG_PM_WAKEUP_TIMES + .poll = suspend_stats_poll, +#endif .release = single_release, }; @@ -234,6 +339,9 @@ static int __init pm_debugfs_init(void) { debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO, NULL, NULL, &suspend_stats_operations); +#ifdef CONFIG_PM_WAKEUP_TIMES + init_waitqueue_head(&suspend_stats_queue.wait_queue); +#endif return 0; } @@ -352,10 +460,147 @@ static suspend_state_t decode_state(const char *buf, size_t n) return PM_SUSPEND_ON; } +static inline u32 +decay_val(u32 val, u32 percent) +{ + u32 ratio; + + percent = clamp(percent, 0U, 100U); + ratio = 1024 - ((1024 * percent) / 100); + + return (val * ratio) / 1024; +} + +static ssize_t sbo_decay_value_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (kstrtoul(buf, 10, &val)) + return -EINVAL; + + if (val > 100) + return -EINVAL; + + sbo_decay_value = val; + return n; +} + +static ssize_t sbo_decay_value_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", sbo_decay_value); +} + +power_attr(sbo_decay_value); + +static ssize_t sbo_short_sleep_msecs_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (kstrtoul(buf, 10, &val)) + return -EINVAL; + + sbo_short_sleep_msecs = val; + return n; +} + +static ssize_t sbo_short_sleep_msecs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", sbo_short_sleep_msecs); +} + +power_attr(sbo_short_sleep_msecs); + +static ssize_t sbo_short_sleep_count_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (kstrtoul(buf, 10, &val)) + return -EINVAL; + + sbo_short_sleep_count = val; + return n; +} + +static ssize_t sbo_short_sleep_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", sbo_short_sleep_count); +} + +power_attr(sbo_short_sleep_count); + +static ssize_t sbo_initial_alive_time_msecs_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (kstrtoul(buf, 10, &val)) + return -EINVAL; + + sbo_initial_alive_time_msecs = val; + return n; +} + +static ssize_t sbo_initial_alive_time_msecs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", sbo_initial_alive_time_msecs); +} + +power_attr(sbo_initial_alive_time_msecs); + +static ssize_t sbo_enabled_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (kstrtoul(buf, 10, &val)) + return -EINVAL; + + if (val > 1) + return -EINVAL; + + sbo_enabled = !!val; + return n; +} + +static ssize_t sbo_enabled_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", sbo_enabled); +} + +power_attr(sbo_enabled); + +static void +suspend_backoff(u32 timeout_msecs) +{ + if (!sbo_enabled) + return; + + pr_info("suspend: too many immediate wakeups, back off (%u msecs)\n", + timeout_msecs); + + __pm_wakeup_event(ws, timeout_msecs); +} + static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { suspend_state_t state; + struct timespec ts_entry, ts_exit; + u64 elapsed_msecs64; + u32 elapsed_msecs32; int error; error = pm_autosleep_lock(); @@ -368,9 +613,48 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, } state = decode_state(buf, n); - if (state < PM_SUSPEND_MAX) + if (state < PM_SUSPEND_MAX) { + /* + * We want to prevent system from frequent periodic wake-ups + * when sleeping time is less or equal certain interval. + * It's done in order to save power in certain cases, one of + * the examples is GPS tracking, but not only. + */ + getnstimeofday(&ts_entry); error = pm_suspend(state); - else if (state == PM_SUSPEND_MAX) + getnstimeofday(&ts_exit); + + elapsed_msecs64 = timespec_to_ns(&ts_exit) - + timespec_to_ns(&ts_entry); + do_div(elapsed_msecs64, NSEC_PER_MSEC); + elapsed_msecs32 = elapsed_msecs64; + + if (elapsed_msecs32 <= sbo_short_sleep_msecs) { + if (suspend_short_count == sbo_short_sleep_count) { + if (decay_alive_time_ms >= MSEC_PER_SEC) { + suspend_backoff(decay_alive_time_ms); + decay_alive_time_ms = + decay_val(decay_alive_time_ms, + sbo_decay_value); + goto out; + } + } else { + suspend_short_count++; + goto out; + } + } + + /* Start from scratch */ + suspend_short_count = 0; + + /* + * Randomize a bit an initial alive time value to be + * not synced with any wake up sources, for example + * IRQs. + */ + decay_alive_time_ms = sbo_initial_alive_time_msecs - + get_random_int() % (sbo_initial_alive_time_msecs / 10); + } else if (state == PM_SUSPEND_MAX) error = hibernate(); else error = -EINVAL; @@ -602,6 +886,11 @@ static struct attribute * g[] = { #ifdef CONFIG_PM_SLEEP &pm_async_attr.attr, &wakeup_count_attr.attr, + &sbo_enabled_attr.attr, + &sbo_decay_value_attr.attr, + &sbo_short_sleep_msecs_attr.attr, + &sbo_short_sleep_count_attr.attr, + &sbo_initial_alive_time_msecs_attr.attr, #ifdef CONFIG_PM_AUTOSLEEP &autosleep_attr.attr, #endif @@ -651,6 +940,10 @@ static int __init pm_init(void) if (error) return error; pm_print_times_init(); + +#ifdef CONFIG_PM_SLEEP + ws = wakeup_source_register("suspend_backoff"); +#endif return pm_autosleep_init(); } diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 58209d8bfc566ef283959a97dfaaff69cfd9196e..0a94d9b0ea1e15b3720613f9068b2bcc817620d8 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -7,6 +7,11 @@ * * This file is released under the GPLv2. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -373,7 +378,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) arch_suspend_disable_irqs(); BUG_ON(!irqs_disabled()); - +#ifdef CONFIG_PM_WAKEUP_TIMES + dpm_log_wakeup_stats(PMSG_SUSPEND); +#endif error = syscore_suspend(); if (!error) { *wakeup = pm_wakeup_pending(); @@ -393,6 +400,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) syscore_resume(); } +#ifdef CONFIG_PM_WAKEUP_TIMES + dpm_log_start_time(PMSG_RESUME); +#endif arch_suspend_enable_irqs(); BUG_ON(irqs_disabled()); @@ -432,6 +442,9 @@ int suspend_devices_and_enter(suspend_state_t state) suspend_console(); suspend_test_start(); +#ifdef CONFIG_PM_WAKEUP_TIMES + dpm_log_start_time(PMSG_SUSPEND); +#endif error = dpm_suspend_start(PMSG_SUSPEND); if (error) { pr_err("PM: Some devices failed to suspend, or early wake event detected\n"); @@ -449,6 +462,9 @@ int suspend_devices_and_enter(suspend_state_t state) Resume_devices: suspend_test_start(); dpm_resume_end(PMSG_RESUME); +#ifdef CONFIG_PM_WAKEUP_TIMES + dpm_log_wakeup_stats(PMSG_RESUME); +#endif suspend_test_finish("resume devices"); trace_suspend_resume(TPS("resume_console"), state, true); resume_console(); @@ -508,9 +524,9 @@ static int enter_state(suspend_state_t state) #ifndef CONFIG_SUSPEND_SKIP_SYNC trace_suspend_resume(TPS("sync_filesystems"), 0, true); - printk(KERN_INFO "PM: Syncing filesystems ... "); + printk(KERN_INFO "PM: Syncing filesystems ...\n"); sys_sync(); - printk("done.\n"); + printk(KERN_INFO "PM: Syncing filesystems ... done.\n"); trace_suspend_resume(TPS("sync_filesystems"), 0, false); #endif diff --git a/kernel/power/wakeup_irq_debug.c b/kernel/power/wakeup_irq_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..eaf659a4d16c8dac709ec9a56e7f76e41eaf12af --- /dev/null +++ b/kernel/power/wakeup_irq_debug.c @@ -0,0 +1,364 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +/* + * Copyright (C) 2015 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "wakeup_debug" + +struct irq_info { + struct list_head list; + unsigned int wakeup_count; + unsigned int irq_count; + char irq_name[128]; + int irq; +}; + +struct wakeup_irq { + struct list_head head; + bool enabled; +}; + +static int update_irq_table(struct wakeup_irq *p, int irq) +{ + struct irq_info *i; + + list_for_each_entry(i, &p->head, list) { + if (i->irq == irq) { + i->irq_count = kstat_irqs_cpu(i->irq, 0); + return 1; + } + } + + return 0; +} + +static void add_irq_to_table(struct wakeup_irq *p, int irq) +{ + struct irq_info *info; + struct irq_desc *desc; + + /* + * TODO: add here a filter for root IRQs + */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + info->irq_count = kstat_irqs_cpu(irq, 0); + info->irq = irq; + + desc = irq_to_desc(irq); + + /* + * IRQ can be disabled and freed, thus + * we save its name because of history + */ + if (desc && desc->action && desc->action->name) + (void) scnprintf( + info->irq_name, sizeof(info->irq_name), + "%s", desc->action->name); + + list_add_tail(&info->list, &p->head); +} + +static int wakeup_irq_suspend(struct device *dev) +{ + struct irq_desc *desc; + struct wakeup_irq *p; + int irq, rv; + + /* get private data */ + p = dev_get_drvdata(dev); + if (!p->enabled) + goto leave; + + /* + * we want to add IRQs to list by reverse way, + * therefore all potential triggered IRQ (nested) + * will be in the beginning of the list + */ + for_each_irq_desc_reverse(irq, desc) { + raw_spin_lock_irq(&desc->lock); + rv = irqd_is_wakeup_set(&desc->irq_data); + raw_spin_unlock_irq(&desc->lock); + + if (rv == 0) + continue; + + rv = update_irq_table(p, irq); + if (rv) + continue; + + add_irq_to_table(p, irq); + dev_dbg(dev, "IRQ %d was added to the list\n", irq); + } + +leave: + return 0; +} + +static int wakeup_irq_resume(struct device *dev) +{ + struct irq_info *i; + struct wakeup_irq *p; + struct irq_desc *desc; + unsigned long flags; + int diff; + + /* get private data */ + p = dev_get_drvdata(dev); + if (!p->enabled) + goto leave; + + /* + * go through all registered IRQs in our list + */ + list_for_each_entry(i, &p->head, list) { + desc = irq_to_desc(i->irq); + if (desc) { + raw_spin_lock_irqsave(&desc->lock, flags); + diff = kstat_irqs_cpu(i->irq, 0) - i->irq_count; + raw_spin_unlock_irqrestore(&desc->lock, flags); + + if (diff > 0) { + i->wakeup_count++; + + dev_dbg(dev, "%d, wake-up count: %d, active: %d (%s)\n", + i->irq, i->wakeup_count, + irqd_is_wakeup_set(&desc->irq_data), + desc->action && desc->action->name ? + desc->action->name : ""); + + log_wakeup_reason(i->irq); + update_irq_table(p, i->irq); + } + } + } + +leave: + return 0; +} + +static ssize_t irq_stat_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wakeup_irq *p; + struct irq_info *i; + int len = 0; + + p = dev_get_drvdata(dev); + + /* build header of the output */ + len += scnprintf(buf + len, PAGE_SIZE - len, + "IRQ\tCount\tName\n"); + + list_for_each_entry(i, &p->head, list) { + if (i->wakeup_count) { + len += scnprintf(buf + len, PAGE_SIZE - len, + "%d\t%d\t%s\n", + i->irq, i->wakeup_count, i->irq_name); + /* + * Ensure we do not write more than PAGE_SIZE + * bytes of data including null terminator and + * add '\n' symbol to the buffer if it's full + */ + if (len >= PAGE_SIZE - 1) { + buf[PAGE_SIZE - 2] = '\n'; + dev_err(dev, "%s:%d: buffer is full\n", + __func__, __LINE__); + break; + } + } + } + + return len; +} + +static ssize_t enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wakeup_irq *p; + + p = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%d\n", p->enabled); +} + +static ssize_t enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wakeup_irq *p; + int value, ret; + + p = dev_get_drvdata(dev); + + ret = kstrtoint(buf, 10, &value); + if (ret) { + dev_err(dev, "kstrtoint failed: %d\n", ret); + goto error; + } + + if (value == 1) + p->enabled = true; + else if (value == 0) + p->enabled = false; + else + goto error; + + return count; + +error: + return -EINVAL; +} + +static const struct dev_pm_ops wakeup_irq_pm_ops = { + .suspend_noirq = wakeup_irq_suspend, + .resume_early = wakeup_irq_resume, +}; + +static struct platform_device wakeup_irq_device = { + .name = MODULE_NAME, + .id = 0, +}; + +static struct platform_driver wakeup_irq_driver = { + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + .pm = &wakeup_irq_pm_ops, + }, +}; + +static struct device_attribute wakeup_irq_attrs[] = { + __ATTR(wakeup_irq_stat, + S_IRUSR | S_IRGRP | S_IROTH, irq_stat_show, NULL), + __ATTR(enable, + S_IRUSR | S_IWUSR, enable_show, enable_store), +}; + +static int create_sysfs_entries(struct device *dev) +{ + int i, rc; + + for (i = 0; i < ARRAY_SIZE(wakeup_irq_attrs); i++) { + rc = device_create_file(dev, &wakeup_irq_attrs[i]); + if (rc < 0) + goto revert; + } + + return 0; + +revert: + for (; --i >= 0;) + device_remove_file(dev, &wakeup_irq_attrs[i]); + + return rc; +} + +static int wakeup_irq_debug_init(void) +{ + struct wakeup_irq *p; + int rv = -1; + + p = kzalloc(sizeof(struct wakeup_irq), GFP_KERNEL); + if (p == NULL) + goto out; + + INIT_LIST_HEAD(&p->head); + + /* + * we need it for PM works correctly + */ + rv = platform_device_register(&wakeup_irq_device); + if (rv) { + pr_err("%s: wakeup_irq_device register failed %d\n", + __func__, rv); + goto free_mem; + } + + rv = platform_driver_register(&wakeup_irq_driver); + if (rv) { + pr_err("%s: wakeup_irq_driver register failed %d\n", + __func__, rv); + goto unregister_device; + } + + rv = create_sysfs_entries(&wakeup_irq_device.dev); + if (rv < 0) { + pr_err("%s: create_sysfs_entries failed %d\n", + __func__, rv); + goto unregister_driver; + } + + /* + * save private data + */ + platform_set_drvdata(&wakeup_irq_device, p); + + /* + * by default it's disabled + */ + p->enabled = false; + return 0; + +unregister_driver: + platform_driver_unregister(&wakeup_irq_driver); +unregister_device: + platform_device_unregister(&wakeup_irq_device); +free_mem: + kzfree(p); +out: + return rv; +} + +static void wakeup_irq_debug_exit(void) +{ + struct irq_info *info, *tmp_info; + struct wakeup_irq *p; + int i; + + p = dev_get_drvdata(&wakeup_irq_device.dev); + + for (i = 0; i < ARRAY_SIZE(wakeup_irq_attrs); i++) + device_remove_file(&wakeup_irq_device.dev, + &wakeup_irq_attrs[i]); + + list_for_each_entry_safe(info, tmp_info, &p->head, list) { + list_del(&info->list); + kzfree(info); + } + + platform_driver_unregister(&wakeup_irq_driver); + platform_device_unregister(&wakeup_irq_device); + kzfree(p); +} + +module_init(wakeup_irq_debug_init); +module_exit(wakeup_irq_debug_exit); + +MODULE_DESCRIPTION("Wakeup IRQ Debug Module"); +MODULE_AUTHOR("Uladzislau Rezki"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 9fcb521fab0e2e3087272473e8d1c7285ba29916..563c046b4b9742c92dcbdd5ae9fd760eba4cbc08 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -15,6 +15,11 @@ * Rewrote bits to get rid of console_lock * 01Mar01 Andrew Morton */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -2110,6 +2115,13 @@ void suspend_console(void) up_console_sem(); } +int is_console_suspended(void) +{ + if (!console_suspend_enabled) + return 0; + return console_suspended; +} + void resume_console(void) { if (!console_suspend_enabled) diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 1ba183e7987c927ef7c530f111b6583e6f66009a..2cb46d51d715caa00ffdcc05c519fc765cdf6fbe 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -248,17 +248,24 @@ static int rcu_gp_in_progress(struct rcu_state *rsp) */ void rcu_sched_qs(void) { - if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.s)) - return; - trace_rcu_grace_period(TPS("rcu_sched"), - __this_cpu_read(rcu_sched_data.gpnum), - TPS("cpuqs")); - __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false); - if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) - return; - __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false); - rcu_report_exp_rdp(&rcu_sched_state, - this_cpu_ptr(&rcu_sched_data), true); + unsigned long flags; + + if (__this_cpu_read(rcu_sched_data.cpu_no_qs.s)) { + trace_rcu_grace_period(TPS("rcu_sched"), + __this_cpu_read(rcu_sched_data.gpnum), + TPS("cpuqs")); + __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false); + if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) + return; + local_irq_save(flags); + if (__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) { + __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false); + rcu_report_exp_rdp(&rcu_sched_state, + this_cpu_ptr(&rcu_sched_data), + true); + } + local_irq_restore(flags); + } } void rcu_bh_qs(void) @@ -295,16 +302,17 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr); * We inform the RCU core by emulating a zero-duration dyntick-idle * period, which we in turn do by incrementing the ->dynticks counter * by two. - * - * The caller must have disabled interrupts. */ static void rcu_momentary_dyntick_idle(void) { + unsigned long flags; struct rcu_data *rdp; struct rcu_dynticks *rdtp; int resched_mask; struct rcu_state *rsp; + local_irq_save(flags); + /* * Yes, we can lose flag-setting operations. This is OK, because * the flag will be set again after some delay. @@ -334,12 +342,13 @@ static void rcu_momentary_dyntick_idle(void) smp_mb__after_atomic(); /* Later stuff after QS. */ break; } + local_irq_restore(flags); } /* * Note a context switch. This is a quiescent state for RCU-sched, * and requires special handling for preemptible RCU. - * The caller must have disabled interrupts. + * The caller must have disabled preemption. */ void rcu_note_context_switch(void) { @@ -369,14 +378,9 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch); */ void rcu_all_qs(void) { - unsigned long flags; - barrier(); /* Avoid RCU read-side critical sections leaking down. */ - if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) { - local_irq_save(flags); + if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) rcu_momentary_dyntick_idle(); - local_irq_restore(flags); - } this_cpu_inc(rcu_qs_ctr); barrier(); /* Avoid RCU read-side critical sections leaking up. */ } diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index c6fc11d626f8515e7d6b20a15be5c0083e6486a7..32cbe72bf5458b1f3d080541d864846c66eb8931 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -147,8 +147,8 @@ static void __init rcu_bootup_announce(void) * the corresponding expedited grace period will also be the end of the * normal grace period. */ -static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp) - __releases(rnp->lock) /* But leaves rrupts disabled. */ +static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp, + unsigned long flags) __releases(rnp->lock) { int blkd_state = (rnp->gp_tasks ? RCU_GP_TASKS : 0) + (rnp->exp_tasks ? RCU_EXP_TASKS : 0) + @@ -236,7 +236,7 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp) rnp->gp_tasks = &t->rcu_node_entry; if (!rnp->exp_tasks && (blkd_state & RCU_EXP_BLKD)) rnp->exp_tasks = &t->rcu_node_entry; - raw_spin_unlock(&rnp->lock); /* rrupts remain disabled. */ + raw_spin_unlock(&rnp->lock); /* * Report the quiescent state for the expedited GP. This expedited @@ -251,6 +251,7 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp) } else { WARN_ON_ONCE(t->rcu_read_unlock_special.b.exp_need_qs); } + local_irq_restore(flags); } /* @@ -285,11 +286,12 @@ static void rcu_preempt_qs(void) * predating the current grace period drain, in other words, until * rnp->gp_tasks becomes NULL. * - * Caller must disable interrupts. + * Caller must disable preemption. */ static void rcu_preempt_note_context_switch(void) { struct task_struct *t = current; + unsigned long flags; struct rcu_data *rdp; struct rcu_node *rnp; @@ -299,7 +301,7 @@ static void rcu_preempt_note_context_switch(void) /* Possibly blocking in an RCU read-side critical section. */ rdp = this_cpu_ptr(rcu_state_p->rda); rnp = rdp->mynode; - raw_spin_lock(&rnp->lock); + raw_spin_lock_irqsave(&rnp->lock, flags); smp_mb__after_unlock_lock(); t->rcu_read_unlock_special.b.blocked = true; t->rcu_blocked_node = rnp; @@ -316,7 +318,7 @@ static void rcu_preempt_note_context_switch(void) (rnp->qsmask & rdp->grpmask) ? rnp->gpnum : rnp->gpnum + 1); - rcu_preempt_ctxt_queue(rnp, rdp); + rcu_preempt_ctxt_queue(rnp, rdp, flags); } else if (t->rcu_read_lock_nesting < 0 && t->rcu_read_unlock_special.s) { diff --git a/kernel/sched/boost.c b/kernel/sched/boost.c index 5bdd51b1e55eb8a0e16b1d452a1b7e22371c2d5e..c23b1aebf3440c709d9304875530fc3ea9f19cef 100644 --- a/kernel/sched/boost.c +++ b/kernel/sched/boost.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include "sched.h" #include @@ -40,6 +45,7 @@ static void boost_kick_cpus(void) { int i; struct cpumask kick_mask; + u32 nr_running; if (boost_policy != SCHED_BOOST_ON_BIG) return; @@ -47,8 +53,20 @@ static void boost_kick_cpus(void) cpumask_andnot(&kick_mask, cpu_online_mask, cpu_isolated_mask); for_each_cpu(i, &kick_mask) { - if (cpu_capacity(i) != max_capacity) - boost_kick(i); + /* + * kick only "small" cluster + */ + if (cpu_capacity(i) != max_capacity) { + nr_running = ACCESS_ONCE(cpu_rq(i)->nr_running); + + /* + * make sense to interrupt CPU if its run-queue + * has something running in order to check for + * migration afterwards, otherwise skip it. + */ + if (nr_running) + boost_kick(i); + } } } diff --git a/kernel/sched/core.c b/kernel/sched/core.c index a992d88545b255617b17d72ec2db003c6deca2a5..3a6bff2187c61804bd7e20241a853fda6f0c44de 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -25,6 +25,11 @@ * 2007-11-29 RT balancing improvements by Steven Rostedt, Gregory Haskins, * Thomas Gleixner, Mike Kravetz */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -621,7 +626,8 @@ void resched_cpu(int cpu) struct rq *rq = cpu_rq(cpu); unsigned long flags; - raw_spin_lock_irqsave(&rq->lock, flags); + if (!raw_spin_trylock_irqsave(&rq->lock, flags)) + return; resched_curr(rq); raw_spin_unlock_irqrestore(&rq->lock, flags); } @@ -2147,7 +2153,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) stat: ttwu_stat(p, cpu, wake_flags); out: - raw_spin_unlock_irqrestore(&p->pi_lock, flags); + raw_spin_unlock(&p->pi_lock); if (freq_notif_allowed) { if (!same_freq_domain(src_cpu, cpu)) { @@ -2160,6 +2166,8 @@ out: } } + local_irq_restore(flags); + return success; } @@ -3511,6 +3519,7 @@ static void __sched notrace __schedule(bool preempt) cpu = smp_processor_id(); rq = cpu_rq(cpu); + rcu_note_context_switch(); prev = rq->curr; /* @@ -3529,16 +3538,13 @@ static void __sched notrace __schedule(bool preempt) if (sched_feat(HRTICK)) hrtick_clear(rq); - local_irq_disable(); - rcu_note_context_switch(); - /* * Make sure that signal_pending_state()->signal_pending() below * can't be reordered with __set_current_state(TASK_INTERRUPTIBLE) * done by the caller to avoid the race with signal_wake_up(). */ smp_mb__before_spinlock(); - raw_spin_lock(&rq->lock); + raw_spin_lock_irq(&rq->lock); lockdep_pin_lock(&rq->lock); rq->clock_skip_update <<= 1; /* promote REQ to ACT */ @@ -6925,9 +6931,6 @@ enum s_alloc { * Build an iteration mask that can exclude certain CPUs from the upwards * domain traversal. * - * Only CPUs that can arrive at this group should be considered to continue - * balancing. - * * Asymmetric node setups can result in situations where the domain tree is of * unequal depth, make sure to skip domains that already cover the entire * range. @@ -6939,31 +6942,18 @@ enum s_alloc { */ static void build_group_mask(struct sched_domain *sd, struct sched_group *sg) { - const struct cpumask *sg_span = sched_group_cpus(sg); + const struct cpumask *span = sched_domain_span(sd); struct sd_data *sdd = sd->private; struct sched_domain *sibling; int i; - for_each_cpu(i, sg_span) { + for_each_cpu(i, span) { sibling = *per_cpu_ptr(sdd->sd, i); - - /* - * Can happen in the asymmetric case, where these siblings are - * unused. The mask will not be empty because those CPUs that - * do have the top domain _should_ span the domain. - */ - if (!sibling->child) - continue; - - /* If we would not end up here, we can't continue from here */ - if (!cpumask_equal(sg_span, sched_domain_span(sibling->child))) + if (!cpumask_test_cpu(i, sched_domain_span(sibling))) continue; cpumask_set_cpu(i, sched_group_mask(sg)); } - - /* We must not have empty masks here */ - WARN_ON_ONCE(cpumask_empty(sched_group_mask(sg))); } /* diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index e12309c1b07b5cbb069984a9fc37a98e11781469..75bfbb336722573c0cd77a3da622a2df6530d609 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -47,7 +47,6 @@ struct sugov_policy { s64 up_rate_delay_ns; s64 down_rate_delay_ns; unsigned int next_freq; - unsigned int cached_raw_freq; /* The next fields are only needed if fast switch cannot be used. */ struct irq_work irq_work; @@ -64,6 +63,7 @@ struct sugov_cpu { struct update_util_data update_util; struct sugov_policy *sg_policy; + unsigned int cached_raw_freq; unsigned long iowait_boost; unsigned long iowait_boost_max; u64 last_update; @@ -72,11 +72,6 @@ struct sugov_cpu { unsigned long util; unsigned long max; unsigned int flags; - - /* The field below is for single-CPU policies only. */ -#ifdef CONFIG_NO_HZ_COMMON - unsigned long saved_idle_calls; -#endif }; static DEFINE_PER_CPU(struct sugov_cpu, sugov_cpu); @@ -132,20 +127,22 @@ static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time, if (sugov_up_down_rate_limit(sg_policy, time, next_freq)) return; - if (sg_policy->next_freq == next_freq) - return; - - sg_policy->next_freq = next_freq; - sg_policy->last_freq_update_time = time; - if (policy->fast_switch_enabled) { + if (sg_policy->next_freq == next_freq) { + trace_cpu_frequency(policy->cur, smp_processor_id()); + return; + } + sg_policy->next_freq = next_freq; + sg_policy->last_freq_update_time = time; next_freq = cpufreq_driver_fast_switch(policy, next_freq); if (next_freq == CPUFREQ_ENTRY_INVALID) return; policy->cur = next_freq; trace_cpu_frequency(next_freq, smp_processor_id()); - } else { + } else if (sg_policy->next_freq != next_freq) { + sg_policy->next_freq = next_freq; + sg_policy->last_freq_update_time = time; sg_policy->work_in_progress = true; irq_work_queue(&sg_policy->irq_work); } @@ -153,7 +150,7 @@ static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time, /** * get_next_freq - Compute a new frequency for a given cpufreq policy. - * @sg_policy: schedutil policy object to compute the new frequency for. + * @sg_cpu: schedutil cpu object to compute the new frequency for. * @util: Current CPU utilization. * @max: CPU capacity. * @@ -173,18 +170,19 @@ static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time, * next_freq (as calculated above) is returned, subject to policy min/max and * cpufreq driver limitations. */ -static unsigned int get_next_freq(struct sugov_policy *sg_policy, - unsigned long util, unsigned long max) +static unsigned int get_next_freq(struct sugov_cpu *sg_cpu, unsigned long util, + unsigned long max) { + struct sugov_policy *sg_policy = sg_cpu->sg_policy; struct cpufreq_policy *policy = sg_policy->policy; unsigned int freq = arch_scale_freq_invariant() ? policy->cpuinfo.max_freq : policy->cur; freq = (freq + (freq >> 2)) * util / max; - if (freq == sg_policy->cached_raw_freq && sg_policy->next_freq != UINT_MAX) + if (freq == sg_cpu->cached_raw_freq && sg_policy->next_freq != UINT_MAX) return sg_policy->next_freq; - sg_policy->cached_raw_freq = freq; + sg_cpu->cached_raw_freq = freq; return cpufreq_driver_resolve_freq(policy, freq); } @@ -250,19 +248,6 @@ static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, unsigned long *util, sg_cpu->iowait_boost >>= 1; } -#ifdef CONFIG_NO_HZ_COMMON -static bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) -{ - unsigned long idle_calls = tick_nohz_get_idle_calls(); - bool ret = idle_calls == sg_cpu->saved_idle_calls; - - sg_cpu->saved_idle_calls = idle_calls; - return ret; -} -#else -static inline bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { return false; } -#endif /* CONFIG_NO_HZ_COMMON */ - static void sugov_update_single(struct update_util_data *hook, u64 time, unsigned int flags) { @@ -271,7 +256,6 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, struct cpufreq_policy *policy = sg_policy->policy; unsigned long util, max; unsigned int next_f; - bool busy; sugov_set_iowait_boost(sg_cpu, time, flags); sg_cpu->last_update = time; @@ -279,37 +263,40 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, if (!sugov_should_update_freq(sg_policy, time)) return; - busy = sugov_cpu_is_busy(sg_cpu); - if (flags & SCHED_CPUFREQ_DL) { next_f = policy->cpuinfo.max_freq; } else { sugov_get_util(&util, &max, time); sugov_iowait_boost(sg_cpu, &util, &max); - next_f = get_next_freq(sg_policy, util, max); - /* - * Do not reduce the frequency if the CPU has not been idle - * recently, as the reduction is likely to be premature then. - */ - if (busy && next_f < sg_policy->next_freq) - next_f = sg_policy->next_freq; + next_f = get_next_freq(sg_cpu, util, max); } sugov_update_commit(sg_policy, time, next_f); } -static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu) +static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, + unsigned long util, unsigned long max, + unsigned int flags) { struct sugov_policy *sg_policy = sg_cpu->sg_policy; struct cpufreq_policy *policy = sg_policy->policy; + unsigned int max_f = policy->cpuinfo.max_freq; u64 last_freq_update_time = sg_policy->last_freq_update_time; - unsigned long util = 0, max = 1; unsigned int j; + if (flags & SCHED_CPUFREQ_DL) + return max_f; + + sugov_iowait_boost(sg_cpu, &util, &max); + for_each_cpu(j, policy->cpus) { - struct sugov_cpu *j_sg_cpu = &per_cpu(sugov_cpu, j); + struct sugov_cpu *j_sg_cpu; unsigned long j_util, j_max; s64 delta_ns; + if (j == smp_processor_id()) + continue; + + j_sg_cpu = &per_cpu(sugov_cpu, j); /* * If the CPU utilization was last updated before the previous * frequency update and the time elapsed between the last update @@ -323,7 +310,7 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu) continue; } if (j_sg_cpu->flags & SCHED_CPUFREQ_DL) - return policy->cpuinfo.max_freq; + return max_f; j_util = j_sg_cpu->util; j_max = j_sg_cpu->max; @@ -335,7 +322,7 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu) sugov_iowait_boost(j_sg_cpu, &util, &max); } - return get_next_freq(sg_policy, util, max); + return get_next_freq(sg_cpu, util, max); } static void sugov_update_shared(struct update_util_data *hook, u64 time, @@ -358,11 +345,7 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time, sg_cpu->last_update = time; if (sugov_should_update_freq(sg_policy, time)) { - if (flags & SCHED_CPUFREQ_DL) - next_f = sg_policy->policy->cpuinfo.max_freq; - else - next_f = sugov_next_freq_shared(sg_cpu); - + next_f = sugov_next_freq_shared(sg_cpu, util, max, flags); sugov_update_commit(sg_policy, time, next_f); } @@ -388,15 +371,15 @@ static void sugov_irq_work(struct irq_work *irq_work) sg_policy = container_of(irq_work, struct sugov_policy, irq_work); /* - * For RT and deadline tasks, the schedutil governor shoots the - * frequency to maximum. Special care must be taken to ensure that this - * kthread doesn't result in the same behavior. + * For Real Time and Deadline tasks, schedutil governor shoots the + * frequency to maximum. And special care must be taken to ensure that + * this kthread doesn't result in that. * * This is (mostly) guaranteed by the work_in_progress flag. The flag is - * updated only at the end of the sugov_work() function and before that - * the schedutil governor rejects all other frequency scaling requests. + * updated only at the end of the sugov_work() and before that schedutil + * rejects all other frequency scaling requests. * - * There is a very rare case though, where the RT thread yields right + * Though there is a very rare case where the RT thread yields right * after the work_in_progress flag is cleared. The effects of that are * neglected for now. */ @@ -506,12 +489,15 @@ static struct sugov_policy *sugov_policy_alloc(struct cpufreq_policy *policy) return NULL; sg_policy->policy = policy; + init_irq_work(&sg_policy->irq_work, sugov_irq_work); + mutex_init(&sg_policy->work_lock); raw_spin_lock_init(&sg_policy->update_lock); return sg_policy; } static void sugov_policy_free(struct sugov_policy *sg_policy) { + mutex_destroy(&sg_policy->work_lock); kfree(sg_policy); } @@ -545,9 +531,6 @@ static int sugov_kthread_create(struct sugov_policy *sg_policy) sg_policy->thread = thread; kthread_bind_mask(thread, policy->related_cpus); - init_irq_work(&sg_policy->irq_work, sugov_irq_work); - mutex_init(&sg_policy->work_lock); - wake_up_process(thread); return 0; @@ -561,7 +544,6 @@ static void sugov_kthread_stop(struct sugov_policy *sg_policy) flush_kthread_worker(&sg_policy->worker); kthread_stop(sg_policy->thread); - mutex_destroy(&sg_policy->work_lock); } static struct sugov_tunables *sugov_tunables_alloc(struct sugov_policy *sg_policy) @@ -596,13 +578,9 @@ static int sugov_init(struct cpufreq_policy *policy) if (policy->governor_data) return -EBUSY; - cpufreq_enable_fast_switch(policy); - sg_policy = sugov_policy_alloc(policy); - if (!sg_policy) { - ret = -ENOMEM; - goto disable_fast_switch; - } + if (!sg_policy) + return -ENOMEM; ret = sugov_kthread_create(sg_policy); if (ret) @@ -645,11 +623,13 @@ static int sugov_init(struct cpufreq_policy *policy) if (ret) goto fail; -out: + out: mutex_unlock(&global_tunables_lock); + + cpufreq_enable_fast_switch(policy); return 0; -fail: + fail: policy->governor_data = NULL; sugov_tunables_free(tunables); @@ -660,10 +640,6 @@ free_sg_policy: mutex_unlock(&global_tunables_lock); sugov_policy_free(sg_policy); - -disable_fast_switch: - cpufreq_disable_fast_switch(policy); - pr_err("initialization failed (error %d)\n", ret); return ret; } @@ -674,6 +650,8 @@ static int sugov_exit(struct cpufreq_policy *policy) struct sugov_tunables *tunables = sg_policy->tunables; unsigned int count; + cpufreq_disable_fast_switch(policy); + mutex_lock(&global_tunables_lock); count = gov_attr_set_put(&tunables->attr_set, &sg_policy->tunables_hook); @@ -686,7 +664,6 @@ static int sugov_exit(struct cpufreq_policy *policy) sugov_kthread_stop(sg_policy); sugov_policy_free(sg_policy); - cpufreq_disable_fast_switch(policy); return 0; } @@ -704,19 +681,25 @@ static int sugov_start(struct cpufreq_policy *policy) sg_policy->next_freq = UINT_MAX; sg_policy->work_in_progress = false; sg_policy->need_freq_update = false; - sg_policy->cached_raw_freq = 0; for_each_cpu(cpu, policy->cpus) { struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu); - memset(sg_cpu, 0, sizeof(*sg_cpu)); sg_cpu->sg_policy = sg_policy; - sg_cpu->flags = SCHED_CPUFREQ_DL; - sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq; - cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util, - policy_is_shared(policy) ? - sugov_update_shared : - sugov_update_single); + if (policy_is_shared(policy)) { + sg_cpu->util = 0; + sg_cpu->max = 0; + sg_cpu->flags = SCHED_CPUFREQ_DL; + sg_cpu->last_update = 0; + sg_cpu->cached_raw_freq = 0; + sg_cpu->iowait_boost = 0; + sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq; + cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util, + sugov_update_shared); + } else { + cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util, + sugov_update_single); + } } return 0; } @@ -731,10 +714,9 @@ static int sugov_stop(struct cpufreq_policy *policy) synchronize_sched(); - if (!policy->fast_switch_enabled) { - irq_work_sync(&sg_policy->irq_work); - kthread_cancel_work_sync(&sg_policy->work); - } + irq_work_sync(&sg_policy->irq_work); + kthread_cancel_work_sync(&sg_policy->work); + return 0; } diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index 14225d5d8617bb6659b2b40b2b8fba85f2c62e3b..1d00cf8c00fa692cecca675a3ec04f111d1b7822 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c @@ -279,14 +279,3 @@ void cpupri_cleanup(struct cpupri *cp) for (i = 0; i < CPUPRI_NR_PRIORITIES; i++) free_cpumask_var(cp->pri_to_cpu[i].mask); } - -/* - * cpupri_check_rt - check if CPU has a RT task - * should be called from rcu-sched read section. - */ -bool cpupri_check_rt(void) -{ - int cpu = raw_smp_processor_id(); - - return cpu_rq(cpu)->rd->cpupri.cpu_to_pri[cpu] > CPUPRI_NORMAL; -} diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 422438d43d9077c56e902be4a498d343df80294b..8c2015ec99fb9f93d9d88f14866ee751c2fff91b 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -19,6 +19,11 @@ * Adaptive scheduling granularity, math enhancements by Peter Zijlstra * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -2747,6 +2752,7 @@ static u32 __compute_runnable_contrib(u64 n) #define SBC_FLAG_BEST_SIBLING 0x200 #define SBC_FLAG_WAKER_CPU 0x400 #define SBC_FLAG_PACK_TASK 0x800 +#define SBC_FLAG_SKIP_RT_TASK 0x1000 /* Cluster selection flag */ #define SBC_FLAG_COLOC_CLUSTER 0x10000 @@ -2983,10 +2989,11 @@ struct cpu_select_env *env, struct cluster_cpu_stats *stats) cpumask_and(&search_cpus, &env->search_cpus, &next->cpus); for_each_cpu(i, &search_cpus) { - trace_sched_cpu_load_wakeup(cpu_rq(i), idle_cpu(i), - sched_irqload(i), power_cost(i, task_load(env->p) + - cpu_cravg_sync(i, env->sync)), 0); - + if (trace_sched_cpu_load_wakeup_enabled()) { + trace_sched_cpu_load_wakeup(cpu_rq(i), idle_cpu(i), + sched_irqload(i), power_cost(i, task_load(env->p) + + cpu_cravg_sync(i, env->sync)), 0); + } update_spare_capacity(stats, env, i, next->capacity, cpu_load_sync(i, env->sync)); } @@ -3027,6 +3034,17 @@ next_best_cluster(struct sched_cluster *cluster, struct cpu_select_env *env, return next; } +/* + * Returns true, if a current task has RT/DL class: + * SCHED_FIFO + SCHED_RR + SCHED_DEADLINE + */ +static inline int +is_current_high_prio_class_task(int cpu) +{ + struct task_struct *curr = READ_ONCE(cpu_rq(cpu)->curr); + return (task_has_rt_policy(curr) | task_has_dl_policy(curr)); +} + #ifdef CONFIG_SCHED_HMP_CSTATE_AWARE static void __update_cluster_stats(int cpu, struct cluster_cpu_stats *stats, struct cpu_select_env *env, int cpu_cost) @@ -3066,6 +3084,25 @@ static void __update_cluster_stats(int cpu, struct cluster_cpu_stats *stats, return; } + /* + * We try to escape of selecting CPUs with running RT + * class tasks, if a power coast is the same. A reason + * is to reduce a latency, since RT task may not be + * preempted for a long time. + */ + if (is_current_high_prio_class_task(stats->best_cpu) && + !is_current_high_prio_class_task(cpu)) { + stats->best_cpu_wakeup_latency = wakeup_latency; + stats->best_load = env->cpu_load; + stats->best_cpu = cpu; + env->sbc_best_flag = SBC_FLAG_SKIP_RT_TASK; + return; + } + + if (!is_current_high_prio_class_task(stats->best_cpu) && + is_current_high_prio_class_task(cpu)) + return; + /* CPU cost is the same. Start breaking the tie by C-state */ if (wakeup_latency > stats->best_cpu_wakeup_latency) @@ -3160,12 +3197,12 @@ static void find_best_cpu_in_cluster(struct sched_cluster *c, for_each_cpu(i, &search_cpus) { env->cpu_load = cpu_load_sync(i, env->sync); - - trace_sched_cpu_load_wakeup(cpu_rq(i), idle_cpu(i), - sched_irqload(i), - power_cost(i, task_load(env->p) + - cpu_cravg_sync(i, env->sync)), 0); - + if (trace_sched_cpu_load_wakeup_enabled()) { + trace_sched_cpu_load_wakeup(cpu_rq(i), idle_cpu(i), + sched_irqload(i), + power_cost(i, task_load(env->p) + + cpu_cravg_sync(i, env->sync)), 0); + } if (skip_cpu(i, env)) continue; @@ -5251,10 +5288,12 @@ static void throttle_cfs_rq(struct cfs_rq *cfs_rq) raw_spin_unlock(&cfs_b->lock); /* Log effect on hmp stats after throttling */ - trace_sched_cpu_load_cgroup(rq, idle_cpu(cpu_of(rq)), - sched_irqload(cpu_of(rq)), - power_cost(cpu_of(rq), 0), - cpu_temp(cpu_of(rq))); + if (trace_sched_cpu_load_cgroup_enabled()) { + trace_sched_cpu_load_cgroup(rq, idle_cpu(cpu_of(rq)), + sched_irqload(cpu_of(rq)), + power_cost(cpu_of(rq), 0), + cpu_temp(cpu_of(rq))); + } } void unthrottle_cfs_rq(struct cfs_rq *cfs_rq) @@ -5308,10 +5347,12 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq) resched_curr(rq); /* Log effect on hmp stats after un-throttling */ - trace_sched_cpu_load_cgroup(rq, idle_cpu(cpu_of(rq)), - sched_irqload(cpu_of(rq)), - power_cost(cpu_of(rq), 0), - cpu_temp(cpu_of(rq))); + if (trace_sched_cpu_load_cgroup_enabled()) { + trace_sched_cpu_load_cgroup(rq, idle_cpu(cpu_of(rq)), + sched_irqload(cpu_of(rq)), + power_cost(cpu_of(rq), 0), + cpu_temp(cpu_of(rq))); + } } static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b, @@ -5887,6 +5928,10 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) if (!se) { add_nr_running(rq, 1); + + if (unlikely(p->nr_cpus_allowed == 1)) + rq->nr_pinned_tasks++; + inc_rq_hmp_stats(rq, p, 1); } @@ -5993,6 +6038,10 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) if (!se) { sub_nr_running(rq, 1); + + if (unlikely(p->nr_cpus_allowed == 1)) + rq->nr_pinned_tasks--; + dec_rq_hmp_stats(rq, p, 1); } @@ -8537,6 +8586,14 @@ redo: if (env->idle != CPU_NOT_IDLE && env->src_rq->nr_running <= 1) break; + /* + * Another CPU can place tasks, since we do not hold dst_rq lock + * while doing balancing. If newly idle CPU already got something, + * give up to reduce a latency. + */ + if (env->idle == CPU_NEWLY_IDLE && env->dst_rq->nr_running > 0) + break; + p = list_first_entry(tasks, struct task_struct, se.group_node); env->loop++; @@ -8559,8 +8616,9 @@ redo: if (sched_feat(LB_MIN) && load < 16 && !env->sd->nr_balance_failed) goto next; - if ((load / 2) > env->imbalance) - goto next; + if (env->idle != CPU_NEWLY_IDLE) + if ((load / 2) > env->imbalance) + goto next; detach_task(p, env); list_add(&p->se.group_node, &env->tasks); @@ -9212,11 +9270,12 @@ static inline void update_sg_lb_stats(struct lb_env *env, for_each_cpu_and(i, sched_group_cpus(group), env->cpus) { struct rq *rq = cpu_rq(i); - trace_sched_cpu_load_lb(cpu_rq(i), idle_cpu(i), - sched_irqload(i), - power_cost(i, 0), - cpu_temp(i)); - + if (trace_sched_cpu_load_lb_enabled()) { + trace_sched_cpu_load_lb(cpu_rq(i), idle_cpu(i), + sched_irqload(i), + power_cost(i, 0), + cpu_temp(i)); + } if (cpu_isolated(i)) continue; @@ -9336,6 +9395,15 @@ static bool update_sd_pick_busiest(struct lb_env *env, if (sgs->group_type < busiest->group_type) return false; + if (sgs->avg_load <= busiest->avg_load) + return false; + + /* + * Group has no more than one task per CPU + */ + if (sgs->sum_nr_running <= sgs->group_weight) + return false; + if (energy_aware()) { /* * Candidate sg doesn't face any serious load-balance problems @@ -9345,9 +9413,6 @@ static bool update_sd_pick_busiest(struct lb_env *env, !group_has_capacity(env, &sds->local_stat)) return false; - if (sgs->avg_load <= busiest->avg_load) - return false; - if (!(env->sd->flags & SD_ASYM_CPUCAPACITY)) goto asym_packing; @@ -10159,7 +10224,6 @@ redo: * correctly treated as an imbalance. */ env.flags |= LBF_ALL_PINNED; - env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running); more_balance: raw_spin_lock_irqsave(&busiest->lock, flags); @@ -10171,6 +10235,12 @@ more_balance: goto no_move; } + /* + * Set loop_max when rq's lock is taken to prevent a race. + */ + env.loop_max = min(sysctl_sched_nr_migrate, + busiest->cfs.h_nr_running); + /* * cur_ld_moved - load moved in current iteration * ld_moved - cumulative load moved across iterations @@ -10654,8 +10724,6 @@ out_unlock: if (p) attach_one_task(target_rq, p); - local_irq_enable(); - if (moved && !same_freq_domain(busiest_cpu, target_cpu)) { int check_groups = !!(env.flags & LBF_MOVED_RELATED_THREAD_GROUP_TASK); @@ -10665,6 +10733,8 @@ out_unlock: check_for_freq_change(target_rq, true, false); } + local_irq_enable(); + return 0; } @@ -11058,6 +11128,22 @@ static inline int _nohz_kick_needed_hmp(struct rq *rq, int cpu, int *type) sched_boost_policy() == SCHED_BOOST_ON_ALL) return 1; + if (unlikely(rq->nr_pinned_tasks > 0)) { + int delta = rq->nr_running - rq->nr_pinned_tasks; + + /* + * Check if it is possible to "unload" this CPU in case + * of having pinned/affine tasks. Do not disturb idle + * core if one of the below condition is true: + * + * - there is one pinned task and it is not "current" + * - all tasks are pinned to this CPU + */ + if (delta < 2) + if (current->nr_cpus_allowed > 1 || !delta) + return 0; + } + if (cpu_max_power_cost(cpu) == max_power_cost) return 1; diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index ae6876e62c0f5b9d9e39f89fe2e99394359fd165..4e6d042da62bc284d9fa0c31d17845fa1f970cc4 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -13,6 +13,11 @@ * Syed Rameez Mustafa, Olav haugan, Joonwoo Park, Pavan Kumar Kondeti * and Vikram Mulukutla */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -136,6 +141,7 @@ struct freq_max_load { static DEFINE_PER_CPU(struct freq_max_load *, freq_max_load); static DEFINE_SPINLOCK(freq_max_load_lock); +static DEFINE_PER_CPU(u64, prev_group_runnable_sum); struct cpu_pwr_stats __weak *get_cpu_pwr_stats(void) { @@ -375,7 +381,6 @@ struct sched_cluster init_cluster = { .dstate_wakeup_energy = 0, .dstate_wakeup_latency = 0, .exec_scale_factor = 1024, - .notifier_sent = 0, .wake_up_idle = 0, }; @@ -552,7 +557,7 @@ static struct sched_cluster *alloc_new_cluster(const struct cpumask *cpus) if (cluster->efficiency < min_possible_efficiency) min_possible_efficiency = cluster->efficiency; - cluster->notifier_sent = 0; + atomic_set(&cluster->notifier_sent, 0); return cluster; } @@ -600,10 +605,16 @@ void update_cluster_topology(void) void init_clusters(void) { + int cpu; + bitmap_clear(all_cluster_ids, 0, NR_CPUS); init_cluster.cpus = *cpu_possible_mask; + atomic_set(&init_cluster.notifier_sent, 0); raw_spin_lock_init(&init_cluster.load_lock); INIT_LIST_HEAD(&cluster_head); + + for_each_possible_cpu(cpu) + per_cpu(prev_group_runnable_sum, cpu) = 0; } int register_cpu_cycle_counter_cb(struct cpu_cycle_counter_cb *cb) @@ -1653,6 +1664,16 @@ static inline u64 scale_exec_time(u64 delta, struct rq *rq) u32 freq; freq = cpu_cycles_to_freq(rq->cc.cycles, rq->cc.time); + + /* + * For some reason, current frequency estimation + * can be far bigger than max available frequency. + * + * TODO: need to be investigated. As for now, take + * min as a workaround. + */ + freq = min(freq, max_possible_freq); + delta = DIV64_U64_ROUNDUP(delta * freq, max_possible_freq); delta *= rq->cluster->exec_scale_factor; delta >>= 10; @@ -1714,6 +1735,8 @@ static void group_load_in_freq_domain(struct cpumask *cpus, } static inline u64 freq_policy_load(struct rq *rq, u64 load); +static inline void commit_prev_group_run_sum(struct rq *rq); +static inline u64 get_prev_group_run_sum(struct rq *rq); /* * Should scheduler alert governor for changing frequency? * @@ -1730,9 +1753,9 @@ static inline u64 freq_policy_load(struct rq *rq, u64 load); static int send_notification(struct rq *rq, int check_pred, int check_groups) { unsigned int cur_freq, freq_required; - unsigned long flags; int rc = 0; - u64 group_load = 0, new_load = 0; + u64 new_load, val = 0; + u32 prev_run_sum, group_run_sum; if (check_pred) { u64 prev = rq->old_busy_time; @@ -1751,19 +1774,19 @@ static int send_notification(struct rq *rq, int check_pred, int check_groups) if (freq_required < cur_freq + sysctl_sched_pred_alert_freq) return 0; } else { - /* - * Protect from concurrent update of rq->prev_runnable_sum and - * group cpu load - */ - raw_spin_lock_irqsave(&rq->lock, flags); + val = get_prev_group_run_sum(rq); + group_run_sum = (u32) (val >> 32); + prev_run_sum = (u32) val; + if (check_groups) - group_load = rq->grp_time.prev_runnable_sum; + /* + * prev_run_sum and group_run_sum are synced + */ + new_load = prev_run_sum + group_run_sum; + else + new_load = prev_run_sum; - new_load = rq->prev_runnable_sum + group_load; new_load = freq_policy_load(rq, new_load); - - raw_spin_unlock_irqrestore(&rq->lock, flags); - cur_freq = load_to_freq(rq, rq->old_busy_time); freq_required = load_to_freq(rq, new_load); @@ -1771,14 +1794,11 @@ static int send_notification(struct rq *rq, int check_pred, int check_groups) return 0; } - raw_spin_lock_irqsave(&rq->lock, flags); - if (!rq->cluster->notifier_sent) { - rq->cluster->notifier_sent = 1; + if (!atomic_cmpxchg(&rq->cluster->notifier_sent, 0, 1)) { rc = 1; trace_sched_freq_alert(cpu_of(rq), check_pred, check_groups, rq, new_load); } - raw_spin_unlock_irqrestore(&rq->lock, flags); return rc; } @@ -1786,14 +1806,11 @@ static int send_notification(struct rq *rq, int check_pred, int check_groups) /* Alert governor if there is a need to change frequency */ void check_for_freq_change(struct rq *rq, bool check_pred, bool check_groups) { - int cpu = cpu_of(rq); - - if (!send_notification(rq, check_pred, check_groups)) - return; - - atomic_notifier_call_chain( - &load_alert_notifier_head, 0, - (void *)(long)cpu); + if (send_notification(rq, check_pred, check_groups)) { + atomic_notifier_call_chain( + &load_alert_notifier_head, 0, + (void *)(long) cpu_of(rq)); + } } void notify_migration(int src_cpu, int dest_cpu, bool src_cpu_dead, @@ -2055,36 +2072,42 @@ void clear_top_tasks_bitmap(unsigned long *bitmap) /* * Special case the last index and provide a fast path for index = 0. - * Note that sched_load_granule can change underneath us if we are not - * holding any runqueue locks while calling the two functions below. */ -static u32 top_task_load(struct rq *rq) +static u32 top_task_load(struct rq *rq) { int index = rq->prev_top; u8 prev = 1 - rq->curr_table; + u32 sched_granule_load; + u32 ret_val = 0; + + sched_granule_load = READ_ONCE(sched_load_granule); if (!index) { int msb = NUM_LOAD_INDICES - 1; - if (!test_bit(msb, rq->top_tasks_bitmap[prev])) - return 0; - else - return sched_load_granule; + if (test_bit(msb, rq->top_tasks_bitmap[prev])) + ret_val = sched_granule_load; } else if (index == NUM_LOAD_INDICES - 1) { - return sched_ravg_window; + ret_val = sched_ravg_window; } else { - return (index + 1) * sched_load_granule; + ret_val = (index + 1) * sched_granule_load; } + + return ret_val; } static int load_to_index(u32 load) { - if (load < sched_load_granule) + u32 sched_granule_load; + + sched_granule_load = READ_ONCE(sched_load_granule); + + if (load < sched_granule_load) return 0; else if (load >= sched_ravg_window) return NUM_LOAD_INDICES - 1; else - return load / sched_load_granule; + return load / sched_granule_load; } static void update_top_tasks(struct task_struct *p, struct rq *rq, @@ -2261,6 +2284,22 @@ static void rollover_cpu_window(struct rq *rq, bool full_window) rq->grp_time.nt_curr_runnable_sum = 0; } +static inline void +commit_prev_group_run_sum(struct rq *rq) +{ + u64 val; + + val = rq->grp_time.prev_runnable_sum; + val = (val << 32) | rq->prev_runnable_sum; + WRITE_ONCE(per_cpu(prev_group_runnable_sum, cpu_of(rq)), val); +} + +static inline u64 +get_prev_group_run_sum(struct rq *rq) +{ + return READ_ONCE(per_cpu(prev_group_runnable_sum, cpu_of(rq))); +} + /* * Account cpu activity in its busy time counters (rq->curr/prev_runnable_sum) */ @@ -2482,7 +2521,7 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq, */ if (mark_start > window_start) { *curr_runnable_sum = scale_exec_time(irqtime, rq); - return; + goto done; } /* @@ -2498,11 +2537,11 @@ static void update_cpu_busy_time(struct task_struct *p, struct rq *rq, /* Process the remaining IRQ busy time in the current window. */ delta = wallclock - window_start; rq->curr_runnable_sum = scale_exec_time(delta, rq); - - return; } done: + commit_prev_group_run_sum(rq); + if (!is_idle_task(p) && !exiting_task(p)) update_top_tasks(p, rq, old_curr_window, new_window, full_window); @@ -2657,7 +2696,7 @@ static void update_history(struct rq *rq, struct task_struct *p, u32 *hist = &p->ravg.sum_history[0]; int ridx, widx; u32 max = 0, avg, demand, pred_demand; - u64 sum = 0; + u64 sum = 0, wma = 0, ewa = 0; /* Ignore windows where task had no activity */ if (!runtime || is_idle_task(p) || exiting_task(p) || !samples) @@ -2669,6 +2708,8 @@ static void update_history(struct rq *rq, struct task_struct *p, for (; ridx >= 0; --widx, --ridx) { hist[widx] = hist[ridx]; sum += hist[widx]; + wma += hist[widx] * (sched_ravg_hist_size - widx); + ewa += hist[widx] << (sched_ravg_hist_size - widx - 1); if (hist[widx] > max) max = hist[widx]; } @@ -2676,6 +2717,8 @@ static void update_history(struct rq *rq, struct task_struct *p, for (widx = 0; widx < samples && widx < sched_ravg_hist_size; widx++) { hist[widx] = runtime; sum += hist[widx]; + wma += hist[widx] * (sched_ravg_hist_size - widx); + ewa += hist[widx] << (sched_ravg_hist_size - widx - 1); if (hist[widx] > max) max = hist[widx]; } @@ -2688,8 +2731,34 @@ static void update_history(struct rq *rq, struct task_struct *p, demand = max; } else { avg = div64_u64(sum, sched_ravg_hist_size); + wma = div64_u64(wma, (sched_ravg_hist_size * (sched_ravg_hist_size + 1)) / 2); + ewa = div64_u64(ewa, (1 << sched_ravg_hist_size) - 1); + if (sched_window_stats_policy == WINDOW_STATS_AVG) demand = avg; + else if (sched_window_stats_policy == WINDOW_STATS_MAX_RECENT_WMA) + /* + * WMA stands for weighted moving average. It helps + * to smooth load curve and react faster while ramping + * down comparing with basic averaging. We do it only + * when load trend goes down. See below example (4 HS): + * + * WMA = (P0 * 4 + P1 * 3 + P2 * 2 + P3 * 1) / (4 + 3 + 2 + 1) + * + * This is done for power saving. Means when load disappears + * or becomes low, this algorithm caches real bottom load faster + * (because of weights) then taking AVG values. + */ + demand = max((u32) wma, runtime); + else if (sched_window_stats_policy == WINDOW_STATS_WMA) + demand = (u32) wma; + else if (sched_window_stats_policy == WINDOW_STATS_MAX_RECENT_EWA) + /* + * EWA stands for exponential weighted average + */ + demand = max((u32) ewa, runtime); + else if (sched_window_stats_policy == WINDOW_STATS_EWA) + demand = (u32) ewa; else demand = max(avg, runtime); } @@ -3057,7 +3126,7 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size) if (window_size) { sched_ravg_window = window_size * TICK_NSEC; set_hmp_defaults(); - sched_load_granule = sched_ravg_window / NUM_LOAD_INDICES; + WRITE_ONCE(sched_load_granule, sched_ravg_window / NUM_LOAD_INDICES); } sched_disable_window_stats = 0; @@ -3070,6 +3139,12 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size) rq->curr_runnable_sum = rq->prev_runnable_sum = 0; rq->nt_curr_runnable_sum = rq->nt_prev_runnable_sum = 0; memset(&rq->grp_time, 0, sizeof(struct group_cpu_time)); + + /* + * just commit zero, since grp_time/prev are 0 + */ + commit_prev_group_run_sum(rq); + for (i = 0; i < NUM_TRACKED_WINDOWS; i++) { memset(&rq->load_subs[i], 0, sizeof(struct load_subtractions)); @@ -3139,6 +3214,8 @@ static inline void account_load_subtractions(struct rq *rq) ls[i].new_subs = 0; } + commit_prev_group_run_sum(rq); + BUG_ON((s64)rq->prev_runnable_sum < 0); BUG_ON((s64)rq->curr_runnable_sum < 0); BUG_ON((s64)rq->nt_prev_runnable_sum < 0); @@ -3225,16 +3302,6 @@ void sched_get_cpus_busy(struct sched_load *busy, max_busy_cpu = cpu; } - /* - * sched_get_cpus_busy() is called for all CPUs in a - * frequency domain. So the notifier_sent flag per - * cluster works even when a frequency domain spans - * more than 1 cluster. - */ - if (rq->cluster->notifier_sent) { - notifier_sent = 1; - rq->cluster->notifier_sent = 0; - } early_detection[i] = (rq->ed_task != NULL); max_freq[i] = cpu_max_freq(cpu); i++; @@ -3285,8 +3352,20 @@ skip_early: i++; } - for_each_cpu(cpu, query_cpus) + for_each_cpu(cpu, query_cpus) { + rq = cpu_rq(cpu); + + /* + * sched_get_cpus_busy() is called for all CPUs in a + * frequency domain. So the notifier_sent flag per + * cluster works even when a frequency domain spans + * more than 1 cluster. + */ + if (atomic_cmpxchg(&rq->cluster->notifier_sent, 1, 0)) + notifier_sent = 1; + raw_spin_unlock(&(cpu_rq(cpu))->lock); + } local_irq_restore(flags); @@ -3652,6 +3731,9 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) dest_rq->ed_task = p; } + commit_prev_group_run_sum(src_rq); + commit_prev_group_run_sum(dest_rq); + done: if (p->state == TASK_WAKING) double_rq_unlock(src_rq, dest_rq); @@ -3850,6 +3932,8 @@ static void transfer_busy_time(struct rq *rq, struct related_thread_group *grp, p->ravg.curr_window_cpu[cpu] = p->ravg.curr_window; p->ravg.prev_window_cpu[cpu] = p->ravg.prev_window; + commit_prev_group_run_sum(rq); + trace_sched_migration_update_sum(p, migrate_type, rq); BUG_ON((s64)*src_curr_runnable_sum < 0); diff --git a/kernel/sched/loadavg.c b/kernel/sched/loadavg.c index f8e8d68ed3fd2547ef867ca01d84f7eee5d059e0..b0b93fd33af9e4bb4d61edcda77d3b761cb9b8de 100644 --- a/kernel/sched/loadavg.c +++ b/kernel/sched/loadavg.c @@ -201,9 +201,8 @@ void calc_load_exit_idle(void) struct rq *this_rq = this_rq(); /* - * If we're still before the pending sample window, we're done. + * If we're still before the sample window, we're done. */ - this_rq->calc_load_update = calc_load_update; if (time_before(jiffies, this_rq->calc_load_update)) return; @@ -212,6 +211,7 @@ void calc_load_exit_idle(void) * accounted through the nohz accounting, so skip the entire deal and * sync up for the next window. */ + this_rq->calc_load_update = calc_load_update; if (time_before(jiffies, this_rq->calc_load_update + 10)) this_rq->calc_load_update += LOAD_FREQ; } diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index ee095f4e7230bb367785a8fda68ebc5ea42d4977..c03d51a017bff8fe5f05262c59d2b5c84c9b352d 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1823,7 +1823,6 @@ static int find_lowest_rq_hmp(struct task_struct *task) * the best one based on our affinity and topology. */ -retry: for_each_sched_cluster(cluster) { if (boost_on_big && cluster->capacity != max_possible_capacity) continue; @@ -1831,15 +1830,6 @@ retry: cpumask_and(&candidate_mask, &cluster->cpus, lowest_mask); cpumask_andnot(&candidate_mask, &candidate_mask, cpu_isolated_mask); - /* - * When placement boost is active, if there is no eligible CPU - * in the highest capacity cluster, we fallback to the other - * clusters. So clear the CPUs of the traversed cluster from - * the lowest_mask. - */ - if (unlikely(boost_on_big)) - cpumask_andnot(lowest_mask, lowest_mask, - &cluster->cpus); if (cpumask_empty(&candidate_mask)) continue; @@ -1879,11 +1869,6 @@ retry: break; } - if (unlikely(boost_on_big && best_cpu == -1)) { - boost_on_big = 0; - goto retry; - } - return best_cpu; } #endif /* CONFIG_SCHED_HMP */ diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 67b7da81f8a221659d96bd773b0490483dff37da..4bb4a4dff76e00b7b8b6bf0e96a83cfa9377c81c 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -395,7 +400,7 @@ struct sched_cluster { bool freq_init_done; int dstate, dstate_wakeup_latency, dstate_wakeup_energy; unsigned int static_cluster_pwr_cost; - int notifier_sent; + atomic_t notifier_sent; bool wake_up_idle; atomic64_t last_cc_update; atomic64_t cycles; @@ -677,6 +682,7 @@ struct rq { * remote CPUs use both these fields when doing load calculation. */ unsigned int nr_running; + unsigned int nr_pinned_tasks; #ifdef CONFIG_NUMA_BALANCING unsigned int nr_numa_running; unsigned int nr_preferred_running; @@ -1080,9 +1086,13 @@ enum sched_boost_policy { #define WINDOW_STATS_MAX 1 #define WINDOW_STATS_MAX_RECENT_AVG 2 #define WINDOW_STATS_AVG 3 -#define WINDOW_STATS_INVALID_POLICY 4 +#define WINDOW_STATS_MAX_RECENT_WMA 4 +#define WINDOW_STATS_WMA 5 +#define WINDOW_STATS_MAX_RECENT_EWA 6 +#define WINDOW_STATS_EWA 7 +#define WINDOW_STATS_INVALID_POLICY 8 -#define SCHED_UPMIGRATE_MIN_NICE 15 +#define SCHED_UPMIGRATE_MIN_NICE 9 #define EXITING_TASK_MARKER 0xdeaddead #define UP_MIGRATION 1 diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 9c56841227cc5f88f3d114332a8a78138a8470e2..a71e94cecdb624261dbe61bd6b44ef19672f5d2d 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -829,6 +829,7 @@ schedtune_boostgroup_init(struct schedtune *st) bg = &per_cpu(cpu_boost_groups, cpu); bg->group[st->idx].boost = 0; bg->group[st->idx].tasks = 0; + raw_spin_lock_init(&bg->lock); } return 0; diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 92c3aae8e056885de326fd211ca72f5f547dc3dd..6e053bd9830c785fdf68de27f635d9380f017cdb 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -72,15 +72,7 @@ static cpumask_t mpc_mask = CPU_MASK_ALL; __read_mostly unsigned int walt_ravg_window = 20000000; /* Min window size (in ns) = 10ms */ -#ifdef CONFIG_HZ_300 -/* - * Tick interval becomes to 3333333 due to - * rounding error when HZ=300. - */ -#define MIN_SCHED_RAVG_WINDOW (3333333 * 6) -#else #define MIN_SCHED_RAVG_WINDOW 10000000 -#endif /* Max window size (in ns) = 1s */ #define MAX_SCHED_RAVG_WINDOW 1000000000 diff --git a/kernel/signal.c b/kernel/signal.c index b92a047ddc8264e939ad3fd163442a8ff0cc5a92..f3f1f7a972fd40f3d437d6bf3b5db2cacaffe6ca 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -503,8 +503,7 @@ int unhandled_signal(struct task_struct *tsk, int sig) return !tsk->ptrace; } -static void collect_signal(int sig, struct sigpending *list, siginfo_t *info, - bool *resched_timer) +static void collect_signal(int sig, struct sigpending *list, siginfo_t *info) { struct sigqueue *q, *first = NULL; @@ -526,12 +525,6 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info, still_pending: list_del_init(&first->list); copy_siginfo(info, &first->info); - - *resched_timer = - (first->flags & SIGQUEUE_PREALLOC) && - (info->si_code == SI_TIMER) && - (info->si_sys_private); - __sigqueue_free(first); } else { /* @@ -548,12 +541,12 @@ still_pending: } static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, - siginfo_t *info, bool *resched_timer) + siginfo_t *info) { int sig = next_signal(pending, mask); if (sig) - collect_signal(sig, pending, info, resched_timer); + collect_signal(sig, pending, info); return sig; } @@ -565,16 +558,15 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, */ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) { - bool resched_timer = false; int signr; /* We only dequeue private signals from ourselves, we don't let * signalfd steal them */ - signr = __dequeue_signal(&tsk->pending, mask, info, &resched_timer); + signr = __dequeue_signal(&tsk->pending, mask, info); if (!signr) { signr = __dequeue_signal(&tsk->signal->shared_pending, - mask, info, &resched_timer); + mask, info); /* * itimer signal ? * @@ -619,7 +611,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) */ current->jobctl |= JOBCTL_STOP_DEQUEUED; } - if (resched_timer) { + if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) { /* * Release the siglock to ensure proper locking order * of timer locks outside of siglocks. Note, we leave diff --git a/kernel/softirq.c b/kernel/softirq.c index 9029227e5f57fb6f297236bd6c3bf2705b90216e..39ffd41594ce62301c74676d1cb24999a243ca62 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -234,8 +234,6 @@ static inline bool lockdep_softirq_start(void) { return false; } static inline void lockdep_softirq_end(bool in_hardirq) { } #endif -#define long_softirq_pending() (local_softirq_pending() & LONG_SOFTIRQ_MASK) -#define defer_for_rt() (long_softirq_pending() && cpupri_check_rt()) asmlinkage __visible void __do_softirq(void) { unsigned long end = jiffies + MAX_SOFTIRQ_TIME; @@ -299,7 +297,6 @@ restart: pending = local_softirq_pending(); if (pending) { if (time_before(jiffies, end) && !need_resched() && - !defer_for_rt() && --max_restart) goto restart; @@ -352,7 +349,7 @@ void irq_enter(void) static inline void invoke_softirq(void) { - if (!force_irqthreads && !defer_for_rt()) { + if (!force_irqthreads) { #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK /* * We can safely execute softirq on the current stack if diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8576e6385d637c3c09af2975f926eee4fe4a0e1c..f27d2ba78d1414b9447ce8e7b22c507179b1ffc1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2380,12 +2380,9 @@ static int do_proc_douintvec_conv(bool *negp, unsigned long *lvalp, if (write) { if (*negp) return -EINVAL; - if (*lvalp > UINT_MAX) - return -EINVAL; *valp = *lvalp; } else { unsigned int val = *valp; - *negp = false; *lvalp = (unsigned long)val; } return 0; diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 333f627a3a3bf4218e73ff0145159089e995a348..ec2102104cb8436e01ea5b7b2cf8c84adde4a7eb 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -896,18 +896,6 @@ ktime_t tick_nohz_get_sleep_length(void) return ts->sleep_length; } -/** - * tick_nohz_get_idle_calls - return the current idle calls counter value - * - * Called from the schedutil frequency scaling governor in scheduler context. - */ -unsigned long tick_nohz_get_idle_calls(void) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - - return ts->idle_calls; -} - static void tick_nohz_account_idle_ticks(struct tick_sched *ts) { #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 738f3467d169ed7d7f4b5b0bbc92826eff9fdf15..5fa544f3f560416c3962b88c7cca392f94dac20e 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -116,26 +116,6 @@ static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta) tk->offs_boot = ktime_add(tk->offs_boot, delta); } -/* - * tk_clock_read - atomic clocksource read() helper - * - * This helper is necessary to use in the read paths because, while the - * seqlock ensures we don't return a bad value while structures are updated, - * it doesn't protect from potential crashes. There is the possibility that - * the tkr's clocksource may change between the read reference, and the - * clock reference passed to the read function. This can cause crashes if - * the wrong clocksource is passed to the wrong read function. - * This isn't necessary to use when holding the timekeeper_lock or doing - * a read of the fast-timekeeper tkrs (which is protected by its own locking - * and update logic). - */ -static inline u64 tk_clock_read(struct tk_read_base *tkr) -{ - struct clocksource *clock = READ_ONCE(tkr->clock); - - return clock->read(clock); -} - #ifdef CONFIG_DEBUG_TIMEKEEPING #define WARNING_FREQ (HZ*300) /* 5 minute rate-limiting */ @@ -193,7 +173,7 @@ static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr) */ do { seq = read_seqcount_begin(&tk_core.seq); - now = tk_clock_read(tkr); + now = tkr->read(tkr->clock); last = tkr->cycle_last; mask = tkr->mask; max = tkr->clock->max_cycles; @@ -227,7 +207,7 @@ static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr) cycle_t cycle_now, delta; /* read clocksource */ - cycle_now = tk_clock_read(tkr); + cycle_now = tkr->read(tkr->clock); /* calculate the delta since the last update_wall_time */ delta = clocksource_delta(cycle_now, tkr->cycle_last, tkr->mask); @@ -255,10 +235,12 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock) old_clock = tk->tkr_mono.clock; tk->tkr_mono.clock = clock; + tk->tkr_mono.read = clock->read; tk->tkr_mono.mask = clock->mask; - tk->tkr_mono.cycle_last = tk_clock_read(&tk->tkr_mono); + tk->tkr_mono.cycle_last = tk->tkr_mono.read(clock); tk->tkr_raw.clock = clock; + tk->tkr_raw.read = clock->read; tk->tkr_raw.mask = clock->mask; tk->tkr_raw.cycle_last = tk->tkr_mono.cycle_last; @@ -422,7 +404,7 @@ static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf) now += timekeeping_delta_to_ns(tkr, clocksource_delta( - tk_clock_read(tkr), + tkr->read(tkr->clock), tkr->cycle_last, tkr->mask)); } while (read_seqcount_retry(&tkf->seq, seq)); @@ -479,10 +461,6 @@ static cycle_t dummy_clock_read(struct clocksource *cs) return cycles_at_suspend; } -static struct clocksource dummy_clock = { - .read = dummy_clock_read, -}; - /** * halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource. * @tk: Timekeeper to snapshot. @@ -499,13 +477,13 @@ static void halt_fast_timekeeper(struct timekeeper *tk) struct tk_read_base *tkr = &tk->tkr_mono; memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy)); - cycles_at_suspend = tk_clock_read(tkr); - tkr_dummy.clock = &dummy_clock; + cycles_at_suspend = tkr->read(tkr->clock); + tkr_dummy.read = dummy_clock_read; update_fast_timekeeper(&tkr_dummy, &tk_fast_mono); tkr = &tk->tkr_raw; memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy)); - tkr_dummy.clock = &dummy_clock; + tkr_dummy.read = dummy_clock_read; update_fast_timekeeper(&tkr_dummy, &tk_fast_raw); } @@ -669,10 +647,11 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) */ static void timekeeping_forward_now(struct timekeeper *tk) { + struct clocksource *clock = tk->tkr_mono.clock; cycle_t cycle_now, delta; s64 nsec; - cycle_now = tk_clock_read(&tk->tkr_mono); + cycle_now = tk->tkr_mono.read(clock); delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask); tk->tkr_mono.cycle_last = cycle_now; tk->tkr_raw.cycle_last = cycle_now; @@ -1455,7 +1434,7 @@ void timekeeping_resume(void) * The less preferred source will only be tried if there is no better * usable source. The rtc part is handled separately in rtc core code. */ - cycle_now = tk_clock_read(&tk->tkr_mono); + cycle_now = tk->tkr_mono.read(clock); if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) && cycle_now > tk->tkr_mono.cycle_last) { u64 num, max = ULLONG_MAX; @@ -1850,7 +1829,7 @@ void update_wall_time(void) #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET offset = real_tk->cycle_interval; #else - offset = clocksource_delta(tk_clock_read(&tk->tkr_mono), + offset = clocksource_delta(tk->tkr_mono.read(tk->tkr_mono.clock), tk->tkr_mono.cycle_last, tk->tkr_mono.mask); #endif diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 048bf074bef9b473a2fae8be9604ebd2df88a952..7093d7abb3dc0eb93d6d5f0f9725fdcb96f6f603 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -132,6 +132,11 @@ config TRACING select EVENT_TRACING select TRACE_CLOCK +config TRACE_PRINTK + bool "Enable trace_printk" + depends on TRACING + default y + config GENERIC_TRACER bool select TRACING diff --git a/kernel/trace/ipc_logging.c b/kernel/trace/ipc_logging.c index ed29c38cd7fbc0ee8c9f07447f4819409cb8116a..fcb2dcf2728c2b3cd279d5359053b818d1eef248 100644 --- a/kernel/trace/ipc_logging.c +++ b/kernel/trace/ipc_logging.c @@ -10,6 +10,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -510,6 +515,13 @@ int ipc_log_string(void *ilctxt, const char *fmt, ...) data_size = vscnprintf((ectxt.buff + ectxt.offset + hdr_size), avail_size, fmt, arg_list); va_end(arg_list); + if (data_size < 0) { + pr_err("%s: vsnprintf failed\n", __func__); + return -EINVAL; + } else if (data_size >= avail_size) { + pr_warn("%s: Truncated log output\n", __func__); + data_size = avail_size - 1; + } tsv_write_header(&ectxt, TSV_TYPE_BYTE_ARRAY, data_size); ectxt.offset += data_size; msg_encode_end(&ectxt); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index a62370731798987447a026733e8c19da23af1351..a76fd3c88eac65c65798b015f7bcc3d1da9ce9ad 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -11,6 +11,11 @@ * Copyright (C) 2004-2006 Ingo Molnar * Copyright (C) 2004 Nadia Yvette Chambers */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -1362,7 +1367,7 @@ static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED; struct saved_cmdlines_buffer { unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1]; unsigned *map_cmdline_to_pid; - unsigned *map_cmdline_to_tgid; + unsigned *saved_tgids; unsigned cmdline_num; int cmdline_idx; char *saved_cmdlines; @@ -1396,10 +1401,9 @@ static int allocate_cmdlines_buffer(unsigned int val, return -ENOMEM; } - s->map_cmdline_to_tgid = kmalloc_array(val, - sizeof(*s->map_cmdline_to_tgid), - GFP_KERNEL); - if (!s->map_cmdline_to_tgid) { + s->saved_tgids = kmalloc_array(val, sizeof(*s->saved_tgids), + GFP_KERNEL); + if (!s->saved_tgids) { kfree(s->map_cmdline_to_pid); kfree(s->saved_cmdlines); return -ENOMEM; @@ -1411,8 +1415,8 @@ static int allocate_cmdlines_buffer(unsigned int val, sizeof(s->map_pid_to_cmdline)); memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP, val * sizeof(*s->map_cmdline_to_pid)); - memset(s->map_cmdline_to_tgid, NO_CMDLINE_MAP, - val * sizeof(*s->map_cmdline_to_tgid)); + memset(s->saved_tgids, 0, + val * sizeof(*s->saved_tgids)); return 0; } @@ -1578,17 +1582,14 @@ static int trace_save_cmdline(struct task_struct *tsk) if (!tsk->pid || unlikely(tsk->pid > PID_MAX_DEFAULT)) return 0; - preempt_disable(); /* * It's not the end of the world if we don't get * the lock, but we also don't want to spin * nor do we want to disable interrupts, * so if we miss here, then better luck next time. */ - if (!arch_spin_trylock(&trace_cmdline_lock)) { - preempt_enable(); + if (!arch_spin_trylock(&trace_cmdline_lock)) return 0; - } idx = savedcmd->map_pid_to_cmdline[tsk->pid]; if (idx == NO_CMDLINE_MAP) { @@ -1611,9 +1612,8 @@ static int trace_save_cmdline(struct task_struct *tsk) } set_cmdline(idx, tsk->comm); - savedcmd->map_cmdline_to_tgid[idx] = tsk->tgid; + savedcmd->saved_tgids[idx] = tsk->tgid; arch_spin_unlock(&trace_cmdline_lock); - preempt_enable(); return 1; } @@ -1655,29 +1655,19 @@ void trace_find_cmdline(int pid, char comm[]) preempt_enable(); } -static int __find_tgid_locked(int pid) +int trace_find_tgid(int pid) { unsigned map; int tgid; + preempt_disable(); + arch_spin_lock(&trace_cmdline_lock); map = savedcmd->map_pid_to_cmdline[pid]; if (map != NO_CMDLINE_MAP) - tgid = savedcmd->map_cmdline_to_tgid[map]; + tgid = savedcmd->saved_tgids[map]; else tgid = -1; - return tgid; -} - -int trace_find_tgid(int pid) -{ - int tgid; - - preempt_disable(); - arch_spin_lock(&trace_cmdline_lock); - - tgid = __find_tgid_locked(pid); - arch_spin_unlock(&trace_cmdline_lock); preempt_enable(); @@ -2069,6 +2059,7 @@ static char *get_trace_buf(void) return this_cpu_ptr(&percpu_buffer->buffer[0]); } +#ifdef CONFIG_TRACE_PRINTK static int alloc_percpu_trace_buffer(void) { struct trace_buffer_struct *buffers; @@ -2109,11 +2100,13 @@ static int alloc_percpu_trace_buffer(void) WARN(1, "Could not allocate percpu trace_printk buffer"); return -ENOMEM; } +#endif static int buffers_allocated; void trace_printk_init_buffers(void) { +#ifdef CONFIG_TRACE_PRINTK if (buffers_allocated) return; @@ -2150,6 +2143,9 @@ void trace_printk_init_buffers(void) */ if (global_trace.trace_buffer.buffer) tracing_start_cmdline_record(); +#else + return; +#endif } void trace_printk_start_comm(void) @@ -3994,15 +3990,10 @@ tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf, { char buf[64]; int r; - unsigned int n; - preempt_disable(); arch_spin_lock(&trace_cmdline_lock); - n = savedcmd->cmdline_num; + r = scnprintf(buf, sizeof(buf), "%u\n", savedcmd->cmdline_num); arch_spin_unlock(&trace_cmdline_lock); - preempt_enable(); - - r = scnprintf(buf, sizeof(buf), "%u\n", n); return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); } @@ -4011,7 +4002,7 @@ static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s) { kfree(s->saved_cmdlines); kfree(s->map_cmdline_to_pid); - kfree(s->map_cmdline_to_tgid); + kfree(s->saved_tgids); kfree(s); } @@ -4028,12 +4019,10 @@ static int tracing_resize_saved_cmdlines(unsigned int val) return -ENOMEM; } - preempt_disable(); arch_spin_lock(&trace_cmdline_lock); savedcmd_temp = savedcmd; savedcmd = s; arch_spin_unlock(&trace_cmdline_lock); - preempt_enable(); free_saved_cmdlines_buffer(savedcmd_temp); return 0; @@ -4252,61 +4241,33 @@ tracing_saved_tgids_read(struct file *file, char __user *ubuf, char *file_buf; char *buf; int len = 0; + int pid; int i; - int *pids; - int n = 0; - - preempt_disable(); - arch_spin_lock(&trace_cmdline_lock); - pids = kmalloc_array(savedcmd->cmdline_num, 2*sizeof(int), GFP_KERNEL); - if (!pids) { - arch_spin_unlock(&trace_cmdline_lock); - preempt_enable(); + file_buf = kmalloc(savedcmd->cmdline_num*(16+1+16), GFP_KERNEL); + if (!file_buf) return -ENOMEM; - } + + buf = file_buf; for (i = 0; i < savedcmd->cmdline_num; i++) { - int pid; + int tgid; + int r; pid = savedcmd->map_cmdline_to_pid[i]; if (pid == -1 || pid == NO_CMDLINE_MAP) continue; - pids[n] = pid; - pids[n+1] = __find_tgid_locked(pid); - n += 2; - } - arch_spin_unlock(&trace_cmdline_lock); - preempt_enable(); - - if (n == 0) { - kfree(pids); - return 0; - } - - /* enough to hold max pair of pids + space, lr and nul */ - len = n * 12; - file_buf = kmalloc(len, GFP_KERNEL); - if (!file_buf) { - kfree(pids); - return -ENOMEM; - } - - buf = file_buf; - for (i = 0; i < n && len > 0; i += 2) { - int r; - - r = snprintf(buf, len, "%d %d\n", pids[i], pids[i+1]); + tgid = trace_find_tgid(pid); + r = sprintf(buf, "%d %d\n", pid, tgid); buf += r; - len -= r; + len += r; } len = simple_read_from_buffer(ubuf, cnt, ppos, - file_buf, buf - file_buf); + file_buf, len); kfree(file_buf); - kfree(pids); return len; } diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index e9092a0247bfbdc4dea6378d235912f78089074b..12ea4ea619eeacc6d679e1f184c4e13b5eed30f7 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -659,25 +659,30 @@ static int create_trace_kprobe(int argc, char **argv) pr_info("Probe point is not specified.\n"); return -EINVAL; } - - /* try to parse an address. if that fails, try to read the - * input as a symbol. */ - if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) { + if (isdigit(argv[1][0])) { + if (is_return) { + pr_info("Return probe point must be a symbol.\n"); + return -EINVAL; + } + /* an address specified */ + ret = kstrtoul(&argv[1][0], 0, (unsigned long *)&addr); + if (ret) { + pr_info("Failed to parse address.\n"); + return ret; + } + } else { /* a symbol specified */ symbol = argv[1]; /* TODO: support .init module functions */ ret = traceprobe_split_symbol_offset(symbol, &offset); if (ret) { - pr_info("Failed to parse either an address or a symbol.\n"); + pr_info("Failed to parse symbol.\n"); return ret; } if (offset && is_return) { pr_info("Return probe must be used without offset.\n"); return -EINVAL; } - } else if (is_return) { - pr_info("Return probe point must be a symbol.\n"); - return -EINVAL; } argc -= 2; argv += 2; diff --git a/lib/Kconfig b/lib/Kconfig index 4bb61d2e6746af641c4bdeffa7e27839b9abfd02..7f6feb7a4687a0d267c020b0b16eb478414a0267 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -547,8 +547,4 @@ config QMI_ENCDEC_DEBUG library. This will log the information regarding the element and message being encoded & decoded. -config STACKDEPOT - bool - select STACKTRACE - endmenu diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 6da96c4f98a56a3f724b5fca727aa9f819d2d45a..20b74735508dc91dabb53028e30048c183ad751e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -244,7 +244,6 @@ config PAGE_OWNER depends on DEBUG_KERNEL && STACKTRACE_SUPPORT select DEBUG_FS select STACKTRACE - select STACKDEPOT select PAGE_EXTENSION help This keeps track of what call chain is the owner of a page, may diff --git a/lib/Makefile b/lib/Makefile index 3ea641eb91bca21a84fe9faf83a963e80f01469b..03a447a234ccfdbc333b0ba4f6c67f1f4fe857bc 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -167,8 +167,6 @@ obj-$(CONFIG_GENERIC_NET_UTILS) += net_utils.o obj-$(CONFIG_SG_SPLIT) += sg_split.o obj-$(CONFIG_STMP_DEVICE) += stmp_device.o -obj-$(CONFIG_STACKDEPOT) += stackdepot.o - libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \ fdt_empty_tree.o $(foreach file, $(libfdt_files), \ diff --git a/lib/bitrev.c b/lib/bitrev.c index 40ffda94cc5dbf79d382ee972a070e24a0bb68e5..998d4482a96af72af9e69d14df9f1e51cbcba823 100644 --- a/lib/bitrev.c +++ b/lib/bitrev.c @@ -1,3 +1,8 @@ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef CONFIG_HAVE_ARCH_BITREVERSE #include #include diff --git a/lib/cmdline.c b/lib/cmdline.c index 79069d7938ea60c2a0f2ca42a205a84070a60c62..8f13cf73c2ecf916c203ef7e963d250a113c3dee 100644 --- a/lib/cmdline.c +++ b/lib/cmdline.c @@ -22,14 +22,14 @@ * the values[M, M+1, ..., N] into the ints array in get_options. */ -static int get_range(char **str, int *pint, int n) +static int get_range(char **str, int *pint) { int x, inc_counter, upper_range; (*str)++; upper_range = simple_strtol((*str), NULL, 0); inc_counter = upper_range - *pint; - for (x = *pint; n && x < upper_range; x++, n--) + for (x = *pint; x < upper_range; x++) *pint++ = x; return inc_counter; } @@ -96,7 +96,7 @@ char *get_options(const char *str, int nints, int *ints) break; if (res == 3) { int range_nums; - range_nums = get_range((char **)&str, ints + i, nints - i); + range_nums = get_range((char **)&str, ints + i); if (range_nums < 0) break; /* diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 771234d050c795c70dd157d40ea1f8840cb7856c..76f29ecba8f404b7c63dc4b1d0887135ab7df48b 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -452,11 +452,11 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT); /* - * For mappings greater than or equal to a page, we limit the stride - * (and hence alignment) to a page size. + * For mappings greater than a page, we limit the stride (and + * hence alignment) to a page size. */ nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; - if (size >= PAGE_SIZE) + if (size > PAGE_SIZE) stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT)); else stride = 1; diff --git a/mm/Kconfig b/mm/Kconfig index b880dce3fafd7e6c74614943a2f8ee6f287d5a7a..0a2f1e6d211f84c932623bfe85f02946f41d18c4 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -557,7 +557,7 @@ config ZPOOL zsmalloc. config ZBUD - tristate "Low density storage for compressed pages" + tristate "Low (Up to 2x) density storage for compressed pages" default n help A special purpose allocator for storing compressed pages. @@ -566,6 +566,16 @@ config ZBUD deterministic reclaim properties that make it preferable to a higher density approach when reclaim will be used. +config Z3FOLD + tristate "Up to 3x density storage for compressed pages" + depends on ZPOOL + default n + help + A special purpose allocator for storing compressed pages. + It is designed to store up to three compressed pages per physical + page. It is a ZBUD derivative so the simplicity and determinism are + still there. + config ZSMALLOC tristate "Memory allocator for compressed pages" depends on MMU diff --git a/mm/Makefile b/mm/Makefile index 130d06ac56e00c2a2a8c6fc91d0c76d0ca20fd22..bb455b4e8bbee0231fd9d0f14c4a4d0f713d4218 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o obj-$(CONFIG_ZPOOL) += zpool.o obj-$(CONFIG_ZBUD) += zbud.o obj-$(CONFIG_ZSMALLOC) += zsmalloc.o +obj-$(CONFIG_Z3FOLD) += z3fold.o obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o obj-$(CONFIG_CMA) += cma.o obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o diff --git a/mm/compaction.c b/mm/compaction.c index f96a58e1843aab7f3a12e992960e142d7ab62e12..87ed50835881e6bab02f4627d967f0ea1b76ba18 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "internal.h" #ifdef CONFIG_COMPACTION @@ -60,27 +59,13 @@ static unsigned long release_freepages(struct list_head *freelist) static void map_pages(struct list_head *list) { - unsigned int i, order, nr_pages; - struct page *page, *next; - LIST_HEAD(tmp_list); - - list_for_each_entry_safe(page, next, list, lru) { - list_del(&page->lru); - - order = page_private(page); - nr_pages = 1 << order; - - post_alloc_hook(page, order, __GFP_MOVABLE); - if (order) - split_page(page, order); + struct page *page; - for (i = 0; i < nr_pages; i++) { - list_add(&page->lru, &tmp_list); - page++; - } + list_for_each_entry(page, list, lru) { + kasan_alloc_pages(page, 0); + arch_alloc_page(page, 0); + kernel_map_pages(page, 1, 1); } - - list_splice(&tmp_list, list); } static inline bool migrate_async_suitable(int migratetype) @@ -457,13 +442,12 @@ static unsigned long isolate_freepages_block(struct compact_control *cc, unsigned long flags = 0; bool locked = false; unsigned long blockpfn = *start_pfn; - unsigned int order; cursor = pfn_to_page(blockpfn); /* Isolate free pages. */ for (; blockpfn < end_pfn; blockpfn++, cursor++) { - int isolated; + int isolated, i; struct page *page = cursor; /* @@ -529,17 +513,17 @@ static unsigned long isolate_freepages_block(struct compact_control *cc, goto isolate_fail; } - /* Found a free page, will break it into order-0 pages */ - order = page_order(page); - isolated = __isolate_free_page(page, order); + /* Found a free page, break it into order-0 pages */ + isolated = split_free_page(page); if (!isolated) break; - set_page_private(page, order); total_isolated += isolated; cc->nr_freepages += isolated; - list_add_tail(&page->lru, freelist); - + for (i = 0; i < isolated; i++) { + list_add(&page->lru, freelist); + page++; + } if (!strict && cc->nr_migratepages <= cc->nr_freepages) { blockpfn += isolated; break; @@ -652,7 +636,7 @@ isolate_freepages_range(struct compact_control *cc, */ } - /* __isolate_free_page() does not map the pages */ + /* split_free_page does not map the pages */ map_pages(&freelist); if (pfn < end_pfn) { @@ -1101,7 +1085,7 @@ static void isolate_freepages(struct compact_control *cc) } } - /* __isolate_free_page() does not map the pages */ + /* split_free_page does not map the pages */ map_pages(freelist); /* diff --git a/mm/debug.c b/mm/debug.c index 3621385c09acc0cfc6b33a262229869af5a8bbc4..5cf26f8c69a37bcd5c025ef43acddbf821c80aa7 100644 --- a/mm/debug.c +++ b/mm/debug.c @@ -9,18 +9,6 @@ #include #include #include -#include -#include - -char *migrate_reason_names[MR_TYPES] = { - "compaction", - "memory_failure", - "memory_hotplug", - "syscall_or_cpuset", - "mempolicy_mbind", - "numa_misplaced", - "cma", -}; static const struct trace_print_flags pageflag_names[] = { {1UL << PG_locked, "locked" }, @@ -118,7 +106,6 @@ void dump_page_badflags(struct page *page, const char *reason, void dump_page(struct page *page, const char *reason) { dump_page_badflags(page, reason, 0); - dump_page_owner(page); } EXPORT_SYMBOL(dump_page); diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 6c6f5ccfcda1a5c642ad8cda241f17915306d23a..5f1ea1e69a68d090bf43940ecd19832e978ed070 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -4,6 +4,11 @@ * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -1363,11 +1368,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, */ if (unlikely(pmd_trans_migrating(*pmdp))) { page = pmd_page(*pmdp); - if (!get_page_unless_zero(page)) - goto out_unlock; spin_unlock(ptl); wait_on_page_locked(page); - put_page(page); goto out; } @@ -1399,11 +1401,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, /* Migration could have started since the pmd_trans_migrating check */ if (!page_locked) { - if (!get_page_unless_zero(page)) - goto out_unlock; spin_unlock(ptl); wait_on_page_locked(page); - put_page(page); page_nid = -1; goto out; } diff --git a/mm/internal.h b/mm/internal.h index 46d27f3788853c7c0e36fa784c213e9ae7f4df87..7b9e313d9dea14da1798eb90fb07dbc5713b64a2 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -182,8 +182,6 @@ extern void prep_compound_page(struct page *page, unsigned int order); #ifdef CONFIG_MEMORY_FAILURE extern bool is_free_buddy_page(struct page *page); #endif -extern void post_alloc_hook(struct page *page, unsigned int order, - gfp_t gfp_flags); extern int user_min_free_kbytes; #if defined CONFIG_COMPACTION || defined CONFIG_CMA diff --git a/mm/list_lru.c b/mm/list_lru.c index 786176b1a0ee1fa898ea3acfc063976a312620ea..5d8dffd5b57c83575b2daf4b9ded58b63c5c6f6e 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -117,7 +117,6 @@ bool list_lru_add(struct list_lru *lru, struct list_head *item) l = list_lru_from_kmem(nlru, item); list_add_tail(item, &l->list); l->nr_items++; - nlru->nr_items++; spin_unlock(&nlru->lock); return true; } @@ -137,7 +136,6 @@ bool list_lru_del(struct list_lru *lru, struct list_head *item) l = list_lru_from_kmem(nlru, item); list_del_init(item); l->nr_items--; - nlru->nr_items--; spin_unlock(&nlru->lock); return true; } @@ -185,10 +183,15 @@ EXPORT_SYMBOL_GPL(list_lru_count_one); unsigned long list_lru_count_node(struct list_lru *lru, int nid) { - struct list_lru_node *nlru; + long count = 0; + int memcg_idx; - nlru = &lru->node[nid]; - return nlru->nr_items; + count += __list_lru_count_one(lru, nid, -1); + if (list_lru_memcg_aware(lru)) { + for_each_memcg_cache_index(memcg_idx) + count += __list_lru_count_one(lru, nid, memcg_idx); + } + return count; } EXPORT_SYMBOL_GPL(list_lru_count_node); @@ -223,7 +226,6 @@ restart: assert_spin_locked(&nlru->lock); case LRU_REMOVED: isolated++; - nlru->nr_items--; /* * If the lru lock has been dropped, our list * traversal is now invalid and so we have to diff --git a/mm/migrate.c b/mm/migrate.c index 85af2816b6d24f94aa41a0ff41379e68f906cf7f..9a5ccfc71afcde5c946ac2ab47025bbe220427cd 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -39,7 +39,6 @@ #include #include #include -#include #include @@ -669,8 +668,6 @@ void migrate_page_copy(struct page *newpage, struct page *page) */ if (PageWriteback(newpage)) end_page_writeback(newpage); - - copy_page_owner(page, newpage); } EXPORT_SYMBOL(migrate_page_copy); @@ -1100,9 +1097,6 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page, goto out; rc = __unmap_and_move(page, newpage, force, mode); - if (rc == MIGRATEPAGE_SUCCESS) { - set_page_owner_migrate_reason(newpage, reason); - } out: if (rc != -EAGAIN) { @@ -1185,7 +1179,7 @@ put_new: static int unmap_and_move_huge_page(new_page_t get_new_page, free_page_t put_new_page, unsigned long private, struct page *hpage, int force, - enum migrate_mode mode, int reason) + enum migrate_mode mode) { int rc = -EAGAIN; int *result = NULL; @@ -1243,7 +1237,6 @@ put_anon: if (rc == MIGRATEPAGE_SUCCESS) { hugetlb_cgroup_migrate(hpage, new_hpage); put_new_page = NULL; - set_page_owner_migrate_reason(new_hpage, reason); } unlock_page(hpage); @@ -1318,7 +1311,7 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page, if (PageHuge(page)) rc = unmap_and_move_huge_page(get_new_page, put_new_page, private, page, - pass > 2, mode, reason); + pass > 2, mode); else rc = unmap_and_move(get_new_page, put_new_page, private, page, pass > 2, mode, @@ -2008,7 +2001,6 @@ fail_putback: set_page_memcg(new_page, page_memcg(page)); set_page_memcg(page, NULL); page_remove_rmap(page); - set_page_owner_migrate_reason(new_page, MR_NUMA_MISPLACED); spin_unlock(ptl); mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end); diff --git a/mm/mmap.c b/mm/mmap.c index 16743bf76a8827721dea8d9936bc34546d39d829..4845723a40ca92e3a79e88c91f31487d87ce4731 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1312,6 +1312,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, *populate = 0; + while (file && (file->f_mode & FMODE_NONMAPPABLE)) + file = file->f_op->get_lower_file(file); + if (!len) return -EINVAL; @@ -2206,7 +2209,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) /* Guard against exceeding limits of the address space. */ address &= PAGE_MASK; - if (address >= (TASK_SIZE & PAGE_MASK)) + if (address >= TASK_SIZE) return -ENOMEM; address += PAGE_SIZE; diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 90515f4d9786edc6416693f3f7cdf38c745e993f..cb86941083373e74e1af389854db7a95889623f5 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -584,6 +584,11 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p, * space under its control. */ do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, true); + trace_oom_sigkill(victim->pid, victim->comm, + victim_points, + get_mm_rss(victim->mm), + oc->gfp_mask); + mark_oom_victim(victim); pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n", task_pid_nr(victim), victim->comm, K(victim->mm->total_vm), diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 6759192e69de3681abd9affe487533ade5b71781..d83ed29341a6169c716e3344951126d9b282946a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -13,6 +13,11 @@ * Per cpu hot/cold page lists, bulk allocation, Martin J. Bligh, Sept 2002 * (lots of bits borrowed from Ingo Molnar & Andrew Morton) */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -223,20 +228,6 @@ static char * const zone_names[MAX_NR_ZONES] = { }; static void free_compound_page(struct page *page); - -char * const migratetype_names[MIGRATE_TYPES] = { - "Unmovable", - "Movable", - "Reclaimable", -#ifdef CONFIG_CMA - "CMA", -#endif - "HighAtomic", -#ifdef CONFIG_MEMORY_ISOLATION - "Isolate", -#endif -}; - compound_page_dtor * const compound_page_dtors[] = { NULL, free_compound_page, @@ -473,7 +464,6 @@ static void bad_page(struct page *page, const char *reason, printk(KERN_ALERT "BUG: Bad page state in process %s pfn:%05lx\n", current->comm, page_to_pfn(page)); dump_page_badflags(page, reason, bad_flags); - dump_page_owner(page); print_modules(); dump_stack(); @@ -584,9 +574,6 @@ static inline void set_page_guard(struct zone *zone, struct page *page, return; page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - return; - __set_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags); INIT_LIST_HEAD(&page->lru); @@ -604,9 +591,6 @@ static inline void clear_page_guard(struct zone *zone, struct page *page, return; page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - return; - __clear_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags); set_page_private(page, 0); @@ -1443,21 +1427,8 @@ static inline bool free_pages_prezeroed(void) page_poisoning_enabled(); } -inline void post_alloc_hook(struct page *page, unsigned int order, - gfp_t gfp_flags) -{ - set_page_private(page, 0); - set_page_refcounted(page); - - kasan_alloc_pages(page, order); - arch_alloc_page(page, order); - kernel_map_pages(page, 1 << order, 1); - kernel_poison_pages(page, 1 << order, 1); - set_page_owner(page, order, gfp_flags); -} - static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags, - int alloc_flags) + int alloc_flags) { int i; @@ -1467,7 +1438,13 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags, return 1; } - post_alloc_hook(page, order, gfp_flags); + set_page_private(page, 0); + set_page_refcounted(page); + + kasan_alloc_pages(page, order); + arch_alloc_page(page, order); + kernel_map_pages(page, 1 << order, 1); + kernel_poison_pages(page, 1 << order, 1); if (!free_pages_prezeroed() && (gfp_flags & __GFP_ZERO)) for (i = 0; i < (1 << order); i++) @@ -1476,6 +1453,8 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags, if (order && (gfp_flags & __GFP_COMP)) prep_compound_page(page, order); + set_page_owner(page, order, gfp_flags); + /* * page is set pfmemalloc when ALLOC_NO_WATERMARKS was necessary to * allocate the page. The expectation is that the caller is taking @@ -2243,6 +2222,7 @@ void free_hot_cold_page_list(struct list_head *list, bool cold) void split_page(struct page *page, unsigned int order) { int i; + gfp_t gfp_mask; VM_BUG_ON_PAGE(PageCompound(page), page); VM_BUG_ON_PAGE(!page_count(page), page); @@ -2256,9 +2236,12 @@ void split_page(struct page *page, unsigned int order) split_page(virt_to_page(page[0].shadow), order); #endif - for (i = 1; i < (1 << order); i++) + gfp_mask = get_page_owner_gfp(page); + set_page_owner(page, 0, gfp_mask); + for (i = 1; i < (1 << order); i++) { set_page_refcounted(page + i); - split_page_owner(page, order); + set_page_owner(page + i, 0, gfp_mask); + } } EXPORT_SYMBOL_GPL(split_page); @@ -2288,6 +2271,8 @@ int __isolate_free_page(struct page *page, unsigned int order) zone->free_area[order].nr_free--; rmv_page_order(page); + set_page_owner(page, order, __GFP_MOVABLE); + /* Set the pageblock if the isolated page is at least a pageblock */ if (order >= pageblock_order - 1) { struct page *endpage = page + (1 << order) - 1; @@ -2304,6 +2289,33 @@ int __isolate_free_page(struct page *page, unsigned int order) return 1UL << order; } +/* + * Similar to split_page except the page is already free. As this is only + * being used for migration, the migratetype of the block also changes. + * As this is called with interrupts disabled, the caller is responsible + * for calling arch_alloc_page() and kernel_map_page() after interrupts + * are enabled. + * + * Note: this is probably too low level an operation for use in drivers. + * Please consult with lkml before using this in your driver. + */ +int split_free_page(struct page *page) +{ + unsigned int order; + int nr_pages; + + order = page_order(page); + + nr_pages = __isolate_free_page(page, order); + if (!nr_pages) + return 0; + + /* Split into individual pages */ + set_page_refcounted(page); + split_page(page, order); + return nr_pages; +} + /* * Allocate a page from the given zone. Use pcplists for order-0 allocations. */ @@ -2818,6 +2830,7 @@ void warn_alloc_failed(gfp_t gfp_mask, unsigned int order, const char *fmt, ...) pr_warn("%s: page allocation failure: order:%u, mode:0x%x\n", current->comm, order, gfp_mask); + trace_mm_page_alloc_fail(order); dump_stack(); if (!should_suppress_show_mem()) show_mem(filter); @@ -3383,6 +3396,9 @@ retry_cpuset: kmemcheck_pagealloc_alloc(page, order, gfp_mask); trace_mm_page_alloc(page, order, alloc_mask, ac.migratetype); + if (order > 1) + trace_mm_page_alloc_highorder(page, order, + alloc_mask, ac.migratetype); out: /* diff --git a/mm/page_isolation.c b/mm/page_isolation.c index efb6c3c38c011bfdf13763e8fe34338b67cef295..3ecd3807c2c2a2372bee0a4baae0208e8bd7c2bd 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "internal.h" static int set_migratetype_isolate(struct page *page, @@ -107,6 +106,10 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype) if (pfn_valid_within(page_to_pfn(buddy)) && !is_migrate_isolate_page(buddy)) { __isolate_free_page(page, order); + kasan_alloc_pages(page, order); + arch_alloc_page(page, order); + kernel_map_pages(page, (1 << order), 1); + set_page_refcounted(page); isolated_page = page; } } @@ -125,10 +128,8 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype) zone->nr_isolate_pageblock--; out: spin_unlock_irqrestore(&zone->lock, flags); - if (isolated_page) { - post_alloc_hook(page, order, __GFP_MOVABLE); + if (isolated_page) __free_pages(isolated_page, order); - } } static inline struct page * diff --git a/mm/page_owner.c b/mm/page_owner.c index 3a9a358e7c63f794e32d75e56ef386881ed95396..45cccaa1ce32f7b5b75b505cfb7696b5957a8964 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -5,24 +5,11 @@ #include #include #include -#include -#include -#include - #include "internal.h" -/* - * TODO: teach PAGE_OWNER_STACK_DEPTH (__dump_page_owner and save_stack) - * to use off stack temporal storage - */ -#define PAGE_OWNER_STACK_DEPTH (16) - static bool page_owner_disabled = !IS_ENABLED(CONFIG_PAGE_OWNER_ENABLE_DEFAULT); -DEFINE_STATIC_KEY_FALSE(page_owner_inited); - -static depot_stack_handle_t dummy_handle; -static depot_stack_handle_t failure_handle; +bool page_owner_inited __read_mostly; static void init_early_allocated_pages(void); @@ -49,42 +36,12 @@ static bool need_page_owner(void) return true; } -static noinline void register_dummy_stack(void) -{ - unsigned long entries[4]; - struct stack_trace dummy; - - dummy.nr_entries = 0; - dummy.max_entries = ARRAY_SIZE(entries); - dummy.entries = &entries[0]; - dummy.skip = 0; - - save_stack_trace(&dummy); - dummy_handle = depot_save_stack(&dummy, GFP_KERNEL); -} - -static noinline void register_failure_stack(void) -{ - unsigned long entries[4]; - struct stack_trace failure; - - failure.nr_entries = 0; - failure.max_entries = ARRAY_SIZE(entries); - failure.entries = &entries[0]; - failure.skip = 0; - - save_stack_trace(&failure); - failure_handle = depot_save_stack(&failure, GFP_KERNEL); -} - static void init_page_owner(void) { if (page_owner_disabled) return; - register_dummy_stack(); - register_failure_stack(); - static_branch_enable(&page_owner_inited); + page_owner_inited = true; init_early_allocated_pages(); } @@ -100,141 +57,46 @@ void __reset_page_owner(struct page *page, unsigned int order) for (i = 0; i < (1 << order); i++) { page_ext = lookup_page_ext(page + i); - if (unlikely(!page_ext)) - continue; __clear_bit(PAGE_EXT_OWNER, &page_ext->flags); } } -static inline bool check_recursive_alloc(struct stack_trace *trace, - unsigned long ip) +void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask) { - int i, count; - - if (!trace->nr_entries) - return false; - - for (i = 0, count = 0; i < trace->nr_entries; i++) { - if (trace->entries[i] == ip && ++count == 2) - return true; - } - - return false; -} - -static noinline depot_stack_handle_t save_stack(gfp_t flags) -{ - unsigned long entries[PAGE_OWNER_STACK_DEPTH]; + struct page_ext *page_ext = lookup_page_ext(page); struct stack_trace trace = { .nr_entries = 0, - .entries = entries, - .max_entries = PAGE_OWNER_STACK_DEPTH, - .skip = 0 + .max_entries = ARRAY_SIZE(page_ext->trace_entries), + .entries = &page_ext->trace_entries[0], + .skip = 3, }; - depot_stack_handle_t handle; save_stack_trace(&trace); - if (trace.nr_entries != 0 && - trace.entries[trace.nr_entries-1] == ULONG_MAX) - trace.nr_entries--; - - /* - * We need to check recursion here because our request to stackdepot - * could trigger memory allocation to save new entry. New memory - * allocation would reach here and call depot_save_stack() again - * if we don't catch it. There is still not enough memory in stackdepot - * so it would try to allocate memory again and loop forever. - */ - if (check_recursive_alloc(&trace, _RET_IP_)) - return dummy_handle; - - handle = depot_save_stack(&trace, flags); - if (!handle) - handle = failure_handle; - - return handle; -} - -noinline void __set_page_owner(struct page *page, unsigned int order, - gfp_t gfp_mask) -{ - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return; - page_ext->handle = save_stack(gfp_mask); page_ext->order = order; page_ext->gfp_mask = gfp_mask; - page_ext->last_migrate_reason = -1; + page_ext->nr_entries = trace.nr_entries; __set_bit(PAGE_EXT_OWNER, &page_ext->flags); } -void __set_page_owner_migrate_reason(struct page *page, int reason) -{ - struct page_ext *page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - return; - - page_ext->last_migrate_reason = reason; -} - -void __split_page_owner(struct page *page, unsigned int order) +gfp_t __get_page_owner_gfp(struct page *page) { - int i; struct page_ext *page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - /* - * The caller just returns if no valid gfp - * So return here too. - */ - return; - page_ext->order = 0; - for (i = 1; i < (1 << order); i++) - __copy_page_owner(page, page + i); -} - -void __copy_page_owner(struct page *oldpage, struct page *newpage) -{ - struct page_ext *old_ext = lookup_page_ext(oldpage); - struct page_ext *new_ext = lookup_page_ext(newpage); - - if (unlikely(!old_ext || !new_ext)) - return; - - new_ext->order = old_ext->order; - new_ext->gfp_mask = old_ext->gfp_mask; - new_ext->last_migrate_reason = old_ext->last_migrate_reason; - new_ext->handle = old_ext->handle; - - /* - * We don't clear the bit on the oldpage as it's going to be freed - * after migration. Until then, the info can be useful in case of - * a bug, and the overal stats will be off a bit only temporarily. - * Also, migrate_misplaced_transhuge_page() can still fail the - * migration and then we want the oldpage to retain the info. But - * in that case we also don't need to explicitly clear the info from - * the new page, which will be freed. - */ - __set_bit(PAGE_EXT_OWNER, &new_ext->flags); + return page_ext->gfp_mask; } static ssize_t print_page_owner(char __user *buf, size_t count, unsigned long pfn, - struct page *page, struct page_ext *page_ext, - depot_stack_handle_t handle) + struct page *page, struct page_ext *page_ext) { int ret; int pageblock_mt, page_mt; char *kbuf; - unsigned long entries[PAGE_OWNER_STACK_DEPTH]; struct stack_trace trace = { - .nr_entries = 0, - .entries = entries, - .max_entries = PAGE_OWNER_STACK_DEPTH, - .skip = 0 + .nr_entries = page_ext->nr_entries, + .entries = &page_ext->trace_entries[0], }; kbuf = kmalloc(count, GFP_KERNEL); @@ -242,9 +104,8 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn, return -ENOMEM; ret = snprintf(kbuf, count, - "Page allocated via order %u, mask %#x(%pGg)\n", - page_ext->order, page_ext->gfp_mask, - &page_ext->gfp_mask); + "Page allocated via order %u, mask 0x%x\n", + page_ext->order, page_ext->gfp_mask); if (ret >= count) goto err; @@ -253,29 +114,31 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn, pageblock_mt = get_pfnblock_migratetype(page, pfn); page_mt = gfpflags_to_migratetype(page_ext->gfp_mask); ret += snprintf(kbuf + ret, count - ret, - "PFN %lu type %s Block %lu type %s Flags %#lx(%pGp)\n", + "PFN %lu Block %lu type %d %s Flags %s%s%s%s%s%s%s%s%s%s%s%s\n", pfn, - migratetype_names[page_mt], pfn >> pageblock_order, - migratetype_names[pageblock_mt], - page->flags, &page->flags); + pageblock_mt, + pageblock_mt != page_mt ? "Fallback" : " ", + PageLocked(page) ? "K" : " ", + PageError(page) ? "E" : " ", + PageReferenced(page) ? "R" : " ", + PageUptodate(page) ? "U" : " ", + PageDirty(page) ? "D" : " ", + PageLRU(page) ? "L" : " ", + PageActive(page) ? "A" : " ", + PageSlab(page) ? "S" : " ", + PageWriteback(page) ? "W" : " ", + PageCompound(page) ? "C" : " ", + PageSwapCache(page) ? "B" : " ", + PageMappedToDisk(page) ? "M" : " "); if (ret >= count) goto err; - depot_fetch_stack(handle, &trace); ret += snprint_stack_trace(kbuf + ret, count - ret, &trace, 0); if (ret >= count) goto err; - if (page_ext->last_migrate_reason != -1) { - ret += snprintf(kbuf + ret, count - ret, - "Page has been migrated, last migrate reason: %s\n", - migrate_reason_names[page_ext->last_migrate_reason]); - if (ret >= count) - goto err; - } - ret += snprintf(kbuf + ret, count - ret, "\n"); if (ret >= count) goto err; @@ -291,58 +154,14 @@ err: return -ENOMEM; } -void __dump_page_owner(struct page *page) -{ - struct page_ext *page_ext = lookup_page_ext(page); - unsigned long entries[PAGE_OWNER_STACK_DEPTH]; - struct stack_trace trace = { - .nr_entries = 0, - .entries = entries, - .max_entries = PAGE_OWNER_STACK_DEPTH, - .skip = 0 - }; - depot_stack_handle_t handle; - gfp_t gfp_mask; - int mt; - - if (unlikely(!page_ext)) { - pr_alert("There is not page extension available.\n"); - return; - } - gfp_mask = page_ext->gfp_mask; - mt = gfpflags_to_migratetype(gfp_mask); - - if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) { - pr_alert("page_owner info is not active (free page?)\n"); - return; - } - - handle = READ_ONCE(page_ext->handle); - if (!handle) { - pr_alert("page_owner info is not active (free page?)\n"); - return; - } - - depot_fetch_stack(handle, &trace); - pr_alert("page allocated via order %u, migratetype %s, " - "gfp_mask %#x(%pGg)\n", page_ext->order, - migratetype_names[mt], gfp_mask, &gfp_mask); - print_stack_trace(&trace, 0); - - if (page_ext->last_migrate_reason != -1) - pr_alert("page has been migrated, last migrate reason: %s\n", - migrate_reason_names[page_ext->last_migrate_reason]); -} - static ssize_t read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long pfn; struct page *page; struct page_ext *page_ext; - depot_stack_handle_t handle; - if (!static_branch_unlikely(&page_owner_inited)) + if (!page_owner_inited) return -EINVAL; page = NULL; @@ -379,8 +198,6 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos) } page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - continue; /* * Some pages could be missed by concurrent allocation or free, @@ -389,19 +206,10 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) continue; - /* - * Access to page_ext->handle isn't synchronous so we should - * be careful to access it. - */ - handle = READ_ONCE(page_ext->handle); - if (!handle) - continue; - /* Record the next PFN to read in the file offset */ *ppos = (pfn - min_low_pfn) + 1; - return print_page_owner(buf, count, pfn, page, - page_ext, handle); + return print_page_owner(buf, count, pfn, page, page_ext); } return 0; @@ -440,9 +248,6 @@ static void init_pages_in_zone(pg_data_t *pgdat, struct zone *zone) page = pfn_to_page(pfn); - if (page_zone(page) != zone) - continue; - /* * We are safe to check buddy flag and order, because * this is init stage and only single thread runs. @@ -456,8 +261,6 @@ static void init_pages_in_zone(pg_data_t *pgdat, struct zone *zone) continue; page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - continue; /* Maybe overraping zone */ if (test_bit(PAGE_EXT_OWNER, &page_ext->flags)) @@ -506,7 +309,7 @@ static int __init pageowner_init(void) { struct dentry *dentry; - if (!static_branch_unlikely(&page_owner_inited)) { + if (!page_owner_inited) { pr_info("page_owner is disabled\n"); return 0; } diff --git a/mm/slub.c b/mm/slub.c index a5f6c6d107e9b35101344e84cfeefd5d12de2bf0..7cf60504a8509d56f8c80c175058394ebcbb79dc 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -8,6 +8,11 @@ * (C) 2007 SGI, Christoph Lameter * (C) 2011 Linux Foundation, Christoph Lameter */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include /* struct reclaim_state */ diff --git a/mm/swap_cgroup.c b/mm/swap_cgroup.c index 09f733b0424af89d665b59c8b63973aaf48e9032..40dd0f9b00d69ce49a805303f3fe936c741347a2 100644 --- a/mm/swap_cgroup.c +++ b/mm/swap_cgroup.c @@ -205,8 +205,6 @@ void swap_cgroup_swapoff(int type) struct page *page = map[i]; if (page) __free_page(page); - if (!(i % SWAP_CLUSTER_MAX)) - cond_resched(); } vfree(map); } diff --git a/mm/vmscan.c b/mm/vmscan.c index 5f6e29f25af90816144a421fdb92f85f7ab5d6c5..94fecacf0ddcc5bad21d96e9635b4587d680912c 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2676,7 +2676,7 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc) if (!populated_zone(zone)) continue; - classzone_idx = gfp_zone(sc->gfp_mask); + classzone_idx = requested_highidx; while (!populated_zone(zone->zone_pgdat->node_zones + classzone_idx)) classzone_idx--; diff --git a/mm/vmstat.c b/mm/vmstat.c index 3c0796cd3f804da1dad2f96128ead1bbb6a8524d..d6b4817c4416930606b1fa52cd98883a2213f6c5 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -927,6 +927,19 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat, #endif #ifdef CONFIG_PROC_FS +static char * const migratetype_names[MIGRATE_TYPES] = { + "Unmovable", + "Movable", + "Reclaimable", +#ifdef CONFIG_CMA + "CMA", +#endif + "HighAtomic", +#ifdef CONFIG_MEMORY_ISOLATION + "Isolate", +#endif +}; + static void frag_show_print(struct seq_file *m, pg_data_t *pgdat, struct zone *zone) { @@ -1090,8 +1103,6 @@ static void pagetypeinfo_showmixedcount_print(struct seq_file *m, continue; page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - continue; if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) continue; @@ -1129,7 +1140,7 @@ static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat) #ifdef CONFIG_PAGE_OWNER int mtype; - if (!static_branch_unlikely(&page_owner_inited)) + if (!page_owner_inited) return; drain_all_pages(NULL); diff --git a/mm/z3fold.c b/mm/z3fold.c new file mode 100644 index 0000000000000000000000000000000000000000..aca0a43494112cd64108aeb57c0bc5b039abc23c --- /dev/null +++ b/mm/z3fold.c @@ -0,0 +1,903 @@ +/* + * z3fold.c + * + * This implementation is based on zbud written by Seth Jennings. + * + * z3fold is an special purpose allocator for storing compressed pages. It + * can store up to three compressed pages per page which improves the + * compression ratio of zbud while retaining its main concepts (e. g. always + * storing an integral number of objects per page) and simplicity. + * It still has simple and deterministic reclaim properties that make it + * preferable to a higher density approach (with no requirement on integral + * number of object per page) when reclaim is used. + * + * As in zbud, pages are divided into "chunks". The size of the chunks is + * fixed at compile time and is determined by NCHUNKS_ORDER below. + * + * z3fold doesn't export any API and is meant to be used via zpool API. + */ +/* + * Copyright (C) 2016 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +/***************** + * Structures +*****************/ +struct z3fold_pool; +struct z3fold_ops { + int (*evict)(struct z3fold_pool *pool, unsigned long handle); +}; + +enum buddy { + HEADLESS = 0, + FIRST, + MIDDLE, + LAST, + BUDDIES_MAX +}; + +/* + * struct z3fold_header - z3fold page metadata occupying the first chunk of each + * z3fold page, except for HEADLESS pages + * @buddy: links the z3fold page into the relevant list in the pool + * @page_lock: per-page lock + * @first_chunks: the size of the first buddy in chunks, 0 if free + * @middle_chunks: the size of the middle buddy in chunks, 0 if free + * @last_chunks: the size of the last buddy in chunks, 0 if free + * @first_num: the starting number (for the first handle) + */ +struct z3fold_header { + struct list_head buddy; + spinlock_t page_lock; + unsigned short first_chunks; + unsigned short middle_chunks; + unsigned short last_chunks; + unsigned short start_middle; + unsigned short first_num:2; +}; + +/* + * NCHUNKS_ORDER determines the internal allocation granularity, effectively + * adjusting internal fragmentation. It also determines the number of + * freelists maintained in each pool. NCHUNKS_ORDER of 6 means that the + * allocation granularity will be in chunks of size PAGE_SIZE/64. Some chunks + * in the beginning of an allocated page are occupied by z3fold header, so + * NCHUNKS will be calculated to 63 (or 62 in case CONFIG_DEBUG_SPINLOCK=y), + * which shows the max number of free chunks in z3fold page, also there will + * be 63, or 62, respectively, freelists per pool. + */ +#define NCHUNKS_ORDER 6 + +#define CHUNK_SHIFT (PAGE_SHIFT - NCHUNKS_ORDER) +#define CHUNK_SIZE (1 << CHUNK_SHIFT) +#define ZHDR_SIZE_ALIGNED round_up(sizeof(struct z3fold_header), CHUNK_SIZE) +#define ZHDR_CHUNKS (ZHDR_SIZE_ALIGNED >> CHUNK_SHIFT) +#define TOTAL_CHUNKS (PAGE_SIZE >> CHUNK_SHIFT) +#define NCHUNKS ((PAGE_SIZE - ZHDR_SIZE_ALIGNED) >> CHUNK_SHIFT) + +#define BUDDY_MASK (0x3) + +/** + * struct z3fold_pool - stores metadata for each z3fold pool + * @name: pool name + * @lock: protects all pool fields and first|last_chunk fields of any + * z3fold page in the pool + * @unbuddied: array of lists tracking z3fold pages that contain 2- buddies; + * the lists each z3fold page is added to depends on the size of + * its free region. + * @buddied: list tracking the z3fold pages that contain 3 buddies; + * these z3fold pages are full + * @lru: list tracking the z3fold pages in LRU order by most recently + * added buddy. + * @pages_nr: number of z3fold pages in the pool. + * @ops: pointer to a structure of user defined operations specified at + * pool creation time. + * + * This structure is allocated at pool creation time and maintains metadata + * pertaining to a particular z3fold pool. + */ +struct z3fold_pool { + const char *name; + spinlock_t lock; + struct list_head unbuddied[NCHUNKS]; + struct list_head buddied; + struct list_head lru; + atomic64_t pages_nr; + const struct z3fold_ops *ops; + struct zpool *zpool; + const struct zpool_ops *zpool_ops; +}; + +/* + * Internal z3fold page flags + */ +enum z3fold_page_flags { + UNDER_RECLAIM = 0, + PAGE_HEADLESS, + MIDDLE_CHUNK_MAPPED, +}; + + +/***************** + * Helpers +*****************/ + +/* Converts an allocation size in bytes to size in z3fold chunks */ +static int size_to_chunks(size_t size) +{ + return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT; +} + +#define for_each_unbuddied_list(_iter, _begin) \ + for ((_iter) = (_begin); (_iter) < NCHUNKS; (_iter)++) + +/* Initializes the z3fold header of a newly allocated z3fold page */ +static struct z3fold_header *init_z3fold_page(struct page *page) +{ + struct z3fold_header *zhdr = page_address(page); + + INIT_LIST_HEAD(&page->lru); + clear_bit(UNDER_RECLAIM, &page->private); + clear_bit(PAGE_HEADLESS, &page->private); + clear_bit(MIDDLE_CHUNK_MAPPED, &page->private); + + spin_lock_init(&zhdr->page_lock); + zhdr->first_chunks = 0; + zhdr->middle_chunks = 0; + zhdr->last_chunks = 0; + zhdr->first_num = 0; + zhdr->start_middle = 0; + INIT_LIST_HEAD(&zhdr->buddy); + return zhdr; +} + +/* Resets the struct page fields and frees the page */ +static void free_z3fold_page(struct z3fold_header *zhdr) +{ + __free_page(virt_to_page(zhdr)); +} + +/* Lock a z3fold page */ +static inline void z3fold_page_lock(struct z3fold_header *zhdr) +{ + spin_lock(&zhdr->page_lock); +} + +/* Unlock a z3fold page */ +static inline void z3fold_page_unlock(struct z3fold_header *zhdr) +{ + spin_unlock(&zhdr->page_lock); +} + + +/* + * Encodes the handle of a particular buddy within a z3fold page + * Pool lock should be held as this function accesses first_num + */ +static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud) +{ + unsigned long handle; + + handle = (unsigned long)zhdr; + if (bud != HEADLESS) + handle += (bud + zhdr->first_num) & BUDDY_MASK; + return handle; +} + +/* Returns the z3fold page where a given handle is stored */ +static struct z3fold_header *handle_to_z3fold_header(unsigned long handle) +{ + return (struct z3fold_header *)(handle & PAGE_MASK); +} + +/* Returns buddy number */ +static enum buddy handle_to_buddy(unsigned long handle) +{ + struct z3fold_header *zhdr = handle_to_z3fold_header(handle); + return (handle - zhdr->first_num) & BUDDY_MASK; +} + +/* + * Returns the number of free chunks in a z3fold page. + * NB: can't be used with HEADLESS pages. + */ +static int num_free_chunks(struct z3fold_header *zhdr) +{ + int nfree; + /* + * If there is a middle object, pick up the bigger free space + * either before or after it. Otherwise just subtract the number + * of chunks occupied by the first and the last objects. + */ + if (zhdr->middle_chunks != 0) { + int nfree_before = zhdr->first_chunks ? + 0 : zhdr->start_middle - ZHDR_CHUNKS; + int nfree_after = zhdr->last_chunks ? + 0 : TOTAL_CHUNKS - + (zhdr->start_middle + zhdr->middle_chunks); + nfree = max(nfree_before, nfree_after); + } else + nfree = NCHUNKS - zhdr->first_chunks - zhdr->last_chunks; + return nfree; +} + +/***************** + * API Functions +*****************/ +/** + * z3fold_create_pool() - create a new z3fold pool + * @gfp: gfp flags when allocating the z3fold pool structure + * @ops: user-defined operations for the z3fold pool + * + * Return: pointer to the new z3fold pool or NULL if the metadata allocation + * failed. + */ +static struct z3fold_pool *z3fold_create_pool(gfp_t gfp, + const struct z3fold_ops *ops) +{ + struct z3fold_pool *pool; + int i; + + pool = kzalloc(sizeof(struct z3fold_pool), gfp); + if (!pool) + return NULL; + spin_lock_init(&pool->lock); + for_each_unbuddied_list(i, 0) + INIT_LIST_HEAD(&pool->unbuddied[i]); + INIT_LIST_HEAD(&pool->buddied); + INIT_LIST_HEAD(&pool->lru); + atomic64_set(&pool->pages_nr, 0); + pool->ops = ops; + return pool; +} + +/** + * z3fold_destroy_pool() - destroys an existing z3fold pool + * @pool: the z3fold pool to be destroyed + * + * The pool should be emptied before this function is called. + */ +static void z3fold_destroy_pool(struct z3fold_pool *pool) +{ + kfree(pool); +} + +static inline void *mchunk_memmove(struct z3fold_header *zhdr, + unsigned short dst_chunk) +{ + void *beg = zhdr; + return memmove(beg + (dst_chunk << CHUNK_SHIFT), + beg + (zhdr->start_middle << CHUNK_SHIFT), + zhdr->middle_chunks << CHUNK_SHIFT); +} + +#define BIG_CHUNK_GAP 3 +/* Has to be called with lock held */ +static int z3fold_compact_page(struct z3fold_header *zhdr) +{ + struct page *page = virt_to_page(zhdr); + + if (test_bit(MIDDLE_CHUNK_MAPPED, &page->private)) + return 0; /* can't move middle chunk, it's used */ + + if (zhdr->middle_chunks == 0) + return 0; /* nothing to compact */ + + if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) { + /* move to the beginning */ + mchunk_memmove(zhdr, ZHDR_CHUNKS); + zhdr->first_chunks = zhdr->middle_chunks; + zhdr->middle_chunks = 0; + zhdr->start_middle = 0; + zhdr->first_num++; + return 1; + } + + /* + * moving data is expensive, so let's only do that if + * there's substantial gain (at least BIG_CHUNK_GAP chunks) + */ + if (zhdr->first_chunks != 0 && zhdr->last_chunks == 0 && + zhdr->start_middle - (zhdr->first_chunks + ZHDR_CHUNKS) >= + BIG_CHUNK_GAP) { + mchunk_memmove(zhdr, zhdr->first_chunks + 1); + zhdr->start_middle = zhdr->first_chunks + 1; + return 1; + } else if (zhdr->last_chunks != 0 && zhdr->first_chunks == 0 && + TOTAL_CHUNKS - (zhdr->last_chunks + zhdr->start_middle + + zhdr->middle_chunks) >= + BIG_CHUNK_GAP) { + unsigned short new_start = NCHUNKS - zhdr->last_chunks - + zhdr->middle_chunks; + mchunk_memmove(zhdr, new_start); + zhdr->start_middle = new_start; + return 1; + } + + return 0; +} + +/** + * z3fold_alloc() - allocates a region of a given size + * @pool: z3fold pool from which to allocate + * @size: size in bytes of the desired allocation + * @gfp: gfp flags used if the pool needs to grow + * @handle: handle of the new allocation + * + * This function will attempt to find a free region in the pool large enough to + * satisfy the allocation request. A search of the unbuddied lists is + * performed first. If no suitable free region is found, then a new page is + * allocated and added to the pool to satisfy the request. + * + * gfp should not set __GFP_HIGHMEM as highmem pages cannot be used + * as z3fold pool pages. + * + * Return: 0 if success and handle is set, otherwise -EINVAL if the size or + * gfp arguments are invalid or -ENOMEM if the pool was unable to allocate + * a new page. + */ +static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp, + unsigned long *handle) +{ + int chunks = 0, i, freechunks; + struct z3fold_header *zhdr = NULL; + enum buddy bud; + struct page *page; + + if (!size || (gfp & __GFP_HIGHMEM)) + return -EINVAL; + + if (size > PAGE_SIZE) + return -ENOSPC; + + if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE) + bud = HEADLESS; + else { + chunks = size_to_chunks(size); + + /* First, try to find an unbuddied z3fold page. */ + zhdr = NULL; + for_each_unbuddied_list(i, chunks) { + spin_lock(&pool->lock); + zhdr = list_first_entry_or_null(&pool->unbuddied[i], + struct z3fold_header, buddy); + if (!zhdr) { + spin_unlock(&pool->lock); + continue; + } + list_del_init(&zhdr->buddy); + spin_unlock(&pool->lock); + + page = virt_to_page(zhdr); + z3fold_page_lock(zhdr); + if (zhdr->first_chunks == 0) { + if (zhdr->middle_chunks != 0 && + chunks >= zhdr->start_middle) + bud = LAST; + else + bud = FIRST; + } else if (zhdr->last_chunks == 0) + bud = LAST; + else if (zhdr->middle_chunks == 0) + bud = MIDDLE; + else { + spin_lock(&pool->lock); + list_add(&zhdr->buddy, &pool->buddied); + spin_unlock(&pool->lock); + z3fold_page_unlock(zhdr); + pr_err("No free chunks in unbuddied\n"); + WARN_ON(1); + continue; + } + goto found; + } + bud = FIRST; + } + + /* Couldn't find unbuddied z3fold page, create new one */ + page = alloc_page(gfp); + if (!page) + return -ENOMEM; + + atomic64_inc(&pool->pages_nr); + zhdr = init_z3fold_page(page); + + if (bud == HEADLESS) { + set_bit(PAGE_HEADLESS, &page->private); + spin_lock(&pool->lock); + goto headless; + } + z3fold_page_lock(zhdr); + +found: + if (bud == FIRST) + zhdr->first_chunks = chunks; + else if (bud == LAST) + zhdr->last_chunks = chunks; + else { + zhdr->middle_chunks = chunks; + zhdr->start_middle = zhdr->first_chunks + ZHDR_CHUNKS; + } + + spin_lock(&pool->lock); + if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0 || + zhdr->middle_chunks == 0) { + /* Add to unbuddied list */ + freechunks = num_free_chunks(zhdr); + list_add(&zhdr->buddy, &pool->unbuddied[freechunks]); + } else { + /* Add to buddied list */ + list_add(&zhdr->buddy, &pool->buddied); + } + +headless: + /* Add/move z3fold page to beginning of LRU */ + if (!list_empty(&page->lru)) + list_del(&page->lru); + + list_add(&page->lru, &pool->lru); + + *handle = encode_handle(zhdr, bud); + spin_unlock(&pool->lock); + if (bud != HEADLESS) + z3fold_page_unlock(zhdr); + + return 0; +} + +/** + * z3fold_free() - frees the allocation associated with the given handle + * @pool: pool in which the allocation resided + * @handle: handle associated with the allocation returned by z3fold_alloc() + * + * In the case that the z3fold page in which the allocation resides is under + * reclaim, as indicated by the PG_reclaim flag being set, this function + * only sets the first|last_chunks to 0. The page is actually freed + * once both buddies are evicted (see z3fold_reclaim_page() below). + */ +static void z3fold_free(struct z3fold_pool *pool, unsigned long handle) +{ + struct z3fold_header *zhdr; + int freechunks; + struct page *page; + enum buddy bud; + + zhdr = handle_to_z3fold_header(handle); + page = virt_to_page(zhdr); + + if (test_bit(PAGE_HEADLESS, &page->private)) { + /* HEADLESS page stored */ + bud = HEADLESS; + } else { + z3fold_page_lock(zhdr); + bud = handle_to_buddy(handle); + + switch (bud) { + case FIRST: + zhdr->first_chunks = 0; + break; + case MIDDLE: + zhdr->middle_chunks = 0; + zhdr->start_middle = 0; + break; + case LAST: + zhdr->last_chunks = 0; + break; + default: + pr_err("%s: unknown bud %d\n", __func__, bud); + WARN_ON(1); + z3fold_page_unlock(zhdr); + return; + } + } + + if (test_bit(UNDER_RECLAIM, &page->private)) { + /* z3fold page is under reclaim, reclaim will free */ + if (bud != HEADLESS) + z3fold_page_unlock(zhdr); + return; + } + + /* Remove from existing buddy list */ + if (bud != HEADLESS) { + spin_lock(&pool->lock); + /* + * this object may have been removed from its list by + * z3fold_alloc(). In that case we just do nothing, + * z3fold_alloc() will allocate an object and add the page + * to the relevant list. + */ + if (!list_empty(&zhdr->buddy)) { + list_del(&zhdr->buddy); + } else { + spin_unlock(&pool->lock); + z3fold_page_unlock(zhdr); + return; + } + spin_unlock(&pool->lock); + } + + if (bud == HEADLESS || + (zhdr->first_chunks == 0 && zhdr->middle_chunks == 0 && + zhdr->last_chunks == 0)) { + /* z3fold page is empty, free */ + spin_lock(&pool->lock); + list_del(&page->lru); + spin_unlock(&pool->lock); + clear_bit(PAGE_HEADLESS, &page->private); + if (bud != HEADLESS) + z3fold_page_unlock(zhdr); + free_z3fold_page(zhdr); + atomic64_dec(&pool->pages_nr); + } else { + z3fold_compact_page(zhdr); + /* Add to the unbuddied list */ + spin_lock(&pool->lock); + freechunks = num_free_chunks(zhdr); + list_add(&zhdr->buddy, &pool->unbuddied[freechunks]); + spin_unlock(&pool->lock); + z3fold_page_unlock(zhdr); + } + +} + +/** + * z3fold_reclaim_page() - evicts allocations from a pool page and frees it + * @pool: pool from which a page will attempt to be evicted + * @retires: number of pages on the LRU list for which eviction will + * be attempted before failing + * + * z3fold reclaim is different from normal system reclaim in that it is done + * from the bottom, up. This is because only the bottom layer, z3fold, has + * information on how the allocations are organized within each z3fold page. + * This has the potential to create interesting locking situations between + * z3fold and the user, however. + * + * To avoid these, this is how z3fold_reclaim_page() should be called: + + * The user detects a page should be reclaimed and calls z3fold_reclaim_page(). + * z3fold_reclaim_page() will remove a z3fold page from the pool LRU list and + * call the user-defined eviction handler with the pool and handle as + * arguments. + * + * If the handle can not be evicted, the eviction handler should return + * non-zero. z3fold_reclaim_page() will add the z3fold page back to the + * appropriate list and try the next z3fold page on the LRU up to + * a user defined number of retries. + * + * If the handle is successfully evicted, the eviction handler should + * return 0 _and_ should have called z3fold_free() on the handle. z3fold_free() + * contains logic to delay freeing the page if the page is under reclaim, + * as indicated by the setting of the PG_reclaim flag on the underlying page. + * + * If all buddies in the z3fold page are successfully evicted, then the + * z3fold page can be freed. + * + * Returns: 0 if page is successfully freed, otherwise -EINVAL if there are + * no pages to evict or an eviction handler is not registered, -EAGAIN if + * the retry limit was hit. + */ +static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries) +{ + int i, ret = 0, freechunks; + struct z3fold_header *zhdr; + struct page *page; + unsigned long first_handle = 0, middle_handle = 0, last_handle = 0; + + spin_lock(&pool->lock); + if (!pool->ops || !pool->ops->evict || retries == 0) { + spin_unlock(&pool->lock); + return -EINVAL; + } + for (i = 0; i < retries; i++) { + if (list_empty(&pool->lru)) { + spin_unlock(&pool->lock); + return -EINVAL; + } + page = list_last_entry(&pool->lru, struct page, lru); + list_del(&page->lru); + + /* Protect z3fold page against free */ + set_bit(UNDER_RECLAIM, &page->private); + zhdr = page_address(page); + if (!test_bit(PAGE_HEADLESS, &page->private)) { + list_del(&zhdr->buddy); + spin_unlock(&pool->lock); + z3fold_page_lock(zhdr); + /* + * We need encode the handles before unlocking, since + * we can race with free that will set + * (first|last)_chunks to 0 + */ + first_handle = 0; + last_handle = 0; + middle_handle = 0; + if (zhdr->first_chunks) + first_handle = encode_handle(zhdr, FIRST); + if (zhdr->middle_chunks) + middle_handle = encode_handle(zhdr, MIDDLE); + if (zhdr->last_chunks) + last_handle = encode_handle(zhdr, LAST); + z3fold_page_unlock(zhdr); + } else { + first_handle = encode_handle(zhdr, HEADLESS); + last_handle = middle_handle = 0; + spin_unlock(&pool->lock); + } + + /* Issue the eviction callback(s) */ + if (middle_handle) { + ret = pool->ops->evict(pool, middle_handle); + if (ret) + goto next; + } + if (first_handle) { + ret = pool->ops->evict(pool, first_handle); + if (ret) + goto next; + } + if (last_handle) { + ret = pool->ops->evict(pool, last_handle); + if (ret) + goto next; + } +next: + if (!test_bit(PAGE_HEADLESS, &page->private)) + z3fold_page_lock(zhdr); + clear_bit(UNDER_RECLAIM, &page->private); + if ((test_bit(PAGE_HEADLESS, &page->private) && ret == 0) || + (zhdr->first_chunks == 0 && zhdr->last_chunks == 0 && + zhdr->middle_chunks == 0)) { + /* + * All buddies are now free, free the z3fold page and + * return success. + */ + if (!test_and_clear_bit(PAGE_HEADLESS, &page->private)) + z3fold_page_unlock(zhdr); + free_z3fold_page(zhdr); + atomic64_dec(&pool->pages_nr); + return 0; + } else if (!test_bit(PAGE_HEADLESS, &page->private)) { + if (zhdr->first_chunks != 0 && + zhdr->last_chunks != 0 && + zhdr->middle_chunks != 0) { + /* Full, add to buddied list */ + spin_lock(&pool->lock); + list_add(&zhdr->buddy, &pool->buddied); + spin_unlock(&pool->lock); + } else { + z3fold_compact_page(zhdr); + /* add to unbuddied list */ + spin_lock(&pool->lock); + freechunks = num_free_chunks(zhdr); + list_add(&zhdr->buddy, + &pool->unbuddied[freechunks]); + spin_unlock(&pool->lock); + } + } + + if (!test_bit(PAGE_HEADLESS, &page->private)) + z3fold_page_unlock(zhdr); + + spin_lock(&pool->lock); + /* add to beginning of LRU */ + list_add(&page->lru, &pool->lru); + } + spin_unlock(&pool->lock); + return -EAGAIN; +} + +/** + * z3fold_map() - maps the allocation associated with the given handle + * @pool: pool in which the allocation resides + * @handle: handle associated with the allocation to be mapped + * + * Extracts the buddy number from handle and constructs the pointer to the + * correct starting chunk within the page. + * + * Returns: a pointer to the mapped allocation + */ +static void *z3fold_map(struct z3fold_pool *pool, unsigned long handle) +{ + struct z3fold_header *zhdr; + struct page *page; + void *addr; + enum buddy buddy; + + zhdr = handle_to_z3fold_header(handle); + addr = zhdr; + page = virt_to_page(zhdr); + + if (test_bit(PAGE_HEADLESS, &page->private)) + goto out; + + z3fold_page_lock(zhdr); + buddy = handle_to_buddy(handle); + switch (buddy) { + case FIRST: + addr += ZHDR_SIZE_ALIGNED; + break; + case MIDDLE: + addr += zhdr->start_middle << CHUNK_SHIFT; + set_bit(MIDDLE_CHUNK_MAPPED, &page->private); + break; + case LAST: + addr += PAGE_SIZE - (zhdr->last_chunks << CHUNK_SHIFT); + break; + default: + pr_err("unknown buddy id %d\n", buddy); + WARN_ON(1); + addr = NULL; + break; + } + + z3fold_page_unlock(zhdr); +out: + return addr; +} + +/** + * z3fold_unmap() - unmaps the allocation associated with the given handle + * @pool: pool in which the allocation resides + * @handle: handle associated with the allocation to be unmapped + */ +static void z3fold_unmap(struct z3fold_pool *pool, unsigned long handle) +{ + struct z3fold_header *zhdr; + struct page *page; + enum buddy buddy; + + zhdr = handle_to_z3fold_header(handle); + page = virt_to_page(zhdr); + + if (test_bit(PAGE_HEADLESS, &page->private)) + return; + + z3fold_page_lock(zhdr); + buddy = handle_to_buddy(handle); + if (buddy == MIDDLE) + clear_bit(MIDDLE_CHUNK_MAPPED, &page->private); + z3fold_page_unlock(zhdr); +} + +/** + * z3fold_get_pool_size() - gets the z3fold pool size in pages + * @pool: pool whose size is being queried + * + * Returns: size in pages of the given pool. + */ +static u64 z3fold_get_pool_size(struct z3fold_pool *pool) +{ + return atomic64_read(&pool->pages_nr); +} + +/***************** + * zpool + ****************/ + +static int z3fold_zpool_evict(struct z3fold_pool *pool, unsigned long handle) +{ + if (pool->zpool && pool->zpool_ops && pool->zpool_ops->evict) + return pool->zpool_ops->evict(pool->zpool, handle); + else + return -ENOENT; +} + +static const struct z3fold_ops z3fold_zpool_ops = { + .evict = z3fold_zpool_evict +}; + +static void *z3fold_zpool_create(const char *name, gfp_t gfp, + const struct zpool_ops *zpool_ops, + struct zpool *zpool) +{ + struct z3fold_pool *pool; + + pool = z3fold_create_pool(gfp, zpool_ops ? &z3fold_zpool_ops : NULL); + if (pool) { + pool->zpool = zpool; + pool->zpool_ops = zpool_ops; + pool->name = name; + } + return pool; +} + +static void z3fold_zpool_destroy(void *pool) +{ + z3fold_destroy_pool(pool); +} + +static int z3fold_zpool_malloc(void *pool, size_t size, gfp_t gfp, + unsigned long *handle) +{ + return z3fold_alloc(pool, size, gfp, handle); +} +static void z3fold_zpool_free(void *pool, unsigned long handle) +{ + z3fold_free(pool, handle); +} + +static int z3fold_zpool_shrink(void *pool, unsigned int pages, + unsigned int *reclaimed) +{ + unsigned int total = 0; + int ret = -EINVAL; + + while (total < pages) { + ret = z3fold_reclaim_page(pool, 8); + if (ret < 0) + break; + total++; + } + + if (reclaimed) + *reclaimed = total; + + return ret; +} + +static void *z3fold_zpool_map(void *pool, unsigned long handle, + enum zpool_mapmode mm) +{ + return z3fold_map(pool, handle); +} +static void z3fold_zpool_unmap(void *pool, unsigned long handle) +{ + z3fold_unmap(pool, handle); +} + +static u64 z3fold_zpool_total_size(void *pool) +{ + return z3fold_get_pool_size(pool) * PAGE_SIZE; +} + +static struct zpool_driver z3fold_zpool_driver = { + .type = "z3fold", + .owner = THIS_MODULE, + .create = z3fold_zpool_create, + .destroy = z3fold_zpool_destroy, + .malloc = z3fold_zpool_malloc, + .free = z3fold_zpool_free, + .shrink = z3fold_zpool_shrink, + .map = z3fold_zpool_map, + .unmap = z3fold_zpool_unmap, + .total_size = z3fold_zpool_total_size, +}; + +MODULE_ALIAS("zpool-z3fold"); + +static int __init init_z3fold(void) +{ + /* Make sure the z3fold header is not larger than the page size */ + BUILD_BUG_ON(ZHDR_SIZE_ALIGNED > PAGE_SIZE); + zpool_register_driver(&z3fold_zpool_driver); + + return 0; +} + +static void __exit exit_z3fold(void) +{ + zpool_unregister_driver(&z3fold_zpool_driver); +} + +module_init(init_z3fold); +module_exit(exit_z3fold); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vitaly Wool "); +MODULE_DESCRIPTION("3-Fold Allocator for Compressed Pages"); diff --git a/mm/zpool.c b/mm/zpool.c index fd3ff719c32cb9cf25dafca9d73f789d8071bad5..58aef91eb1e17bcab40cdbd301db691039dc15ee 100644 --- a/mm/zpool.c +++ b/mm/zpool.c @@ -6,6 +6,11 @@ * This is a common frontend for memory storage pool implementations. * Typically, this is used to store compressed memory. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -355,6 +360,32 @@ u64 zpool_get_total_size(struct zpool *zpool) return zpool->driver->total_size(zpool->pool); } +/** + * zpool_compact() - trigger backend-specific pool compaction + * @pool The zpool to compact + * + * This returns the total size in bytes of the pool. + * + * Returns: Number of pages compacted + */ +unsigned long zpool_compact(struct zpool *zpool) +{ + return zpool->driver->compact ? + zpool->driver->compact(zpool->pool) : 0; +} + +/** + * zpool_get_num_compacted() - get the number of migrated/compacted pages + * @stats stats to fill in + * + * Returns: the total number of migrated pages for the pool + */ +unsigned long zpool_get_num_compacted(struct zpool *zpool) +{ + return zpool->driver->get_num_compacted ? + zpool->driver->get_num_compacted(zpool->pool) : 0; +} + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dan Streetman "); MODULE_DESCRIPTION("Common API for compressed memory storage"); diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 1eb00e3435235054129d24a009bdff5ed4958e4d..46d0741aeecad2bb09b8974b702c1f976104c771 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -10,6 +10,11 @@ * Released under the terms of 3-clause BSD License * Released under the terms of GNU General Public License Version 2.0 */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ /* * Following is how we use various fields and flags of underlying @@ -449,6 +454,20 @@ static u64 zs_zpool_total_size(void *pool) return zs_get_total_pages(pool) << PAGE_SHIFT; } +static unsigned long zs_zpool_compact(void *pool) +{ + return zs_compact(pool); +} + +static unsigned long zs_zpool_get_compacted(void *pool) +{ + struct zs_pool_stats stats; + + zs_pool_stats(pool, &stats); + return stats.pages_compacted; +} + + static struct zpool_driver zs_zpool_driver = { .type = "zsmalloc", .owner = THIS_MODULE, @@ -460,6 +479,8 @@ static struct zpool_driver zs_zpool_driver = { .map = zs_zpool_map, .unmap = zs_zpool_unmap, .total_size = zs_zpool_total_size, + .compact = zs_zpool_compact, + .get_num_compacted = zs_zpool_get_compacted, }; MODULE_ALIAS("zpool-zsmalloc"); diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index e20ae2d3c498080967f369e7558b473757419b59..ad8d6e6b87cab9c2c03c9e317513880d1b755b95 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -278,8 +278,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) return 0; out_free_newdev: - if (new_dev->reg_state == NETREG_UNINITIALIZED) - free_netdev(new_dev); + free_netdev(new_dev); return err; } diff --git a/net/Kconfig b/net/Kconfig index 5cff5877d7d17860138221be8aed8d74b06c10ad..dd79708d42625c7d7c85fca956cd302231d41461 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -102,6 +102,14 @@ config ANDROID_PARANOID_NETWORK help none +config NET_ACTIVITY_STATS + bool "Network activity statistics tracking" + default y + help + Network activity statistics are useful for tracking wireless + modem activity on 2G, 3G, 4G wireless networks. Counts number of + transmissions and groups them in specified time buckets. + config NETWORK_SECMARK bool "Security Marking" help diff --git a/net/Makefile b/net/Makefile index e700aa62b1afecfa54e696415779b27d995446cd..fa0c1077b2a12d1590c87044e5824fed6294599f 100644 --- a/net/Makefile +++ b/net/Makefile @@ -79,3 +79,4 @@ obj-y += l3mdev/ endif obj-$(CONFIG_IPC_ROUTER) += ipc_router/ obj-$(CONFIG_RMNET_DATA) += rmnet_data/ +obj-$(CONFIG_NET_ACTIVITY_STATS) += activity_stats.o diff --git a/net/activity_stats.c b/net/activity_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..bc568b58c85e299f329378a65db04d840bcd23f6 --- /dev/null +++ b/net/activity_stats.c @@ -0,0 +1,121 @@ +/* net/activity_stats.c + * + * Copyright (C) 2010 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. + * + * Author: Mike Chan (mike@android.com) + */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ + +#include +#include +#include +#include + +/* + * Track transmission rates in buckets (power of 2). + * 1,2,4,8...512 seconds. + * + * Buckets represent the count of network transmissions at least + * N seconds apart, where N is 1 << bucket index. + */ +#define BUCKET_MAX 10 + +/* Track network activity frequency */ +static unsigned long activity_stats[BUCKET_MAX]; +static ktime_t last_transmit; +static ktime_t suspend_time; +static DEFINE_SPINLOCK(activity_lock); + +void activity_stats_update(void) +{ + int i; + unsigned long flags; + ktime_t now; + s64 delta; + + spin_lock_irqsave(&activity_lock, flags); + now = ktime_get(); + delta = ktime_to_ns(ktime_sub(now, last_transmit)); + + for (i = BUCKET_MAX - 1; i >= 0; i--) { + /* + * Check if the time delta between network activity is within the + * minimum bucket range. + */ + if (delta < (1000000000ULL << i)) + continue; + + activity_stats[i]++; + last_transmit = now; + break; + } + spin_unlock_irqrestore(&activity_lock, flags); +} + +static int activity_stats_show(struct seq_file *m, void *v) +{ + int i; + + seq_printf(m, "Min Bucket(sec) Count\n"); + + for (i = 0; i < BUCKET_MAX; i++) { + seq_printf(m, "%15d %lu\n", 1 << i, activity_stats[i]); + } + + return 0; +} + +static int activity_stats_notifier(struct notifier_block *nb, + unsigned long event, void *dummy) +{ + switch (event) { + case PM_SUSPEND_PREPARE: + suspend_time = ktime_get_real(); + break; + + case PM_POST_SUSPEND: + suspend_time = ktime_sub(ktime_get_real(), suspend_time); + last_transmit = ktime_sub(last_transmit, suspend_time); + } + + return 0; +} + +static int activity_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, activity_stats_show, PDE_DATA(inode)); +} + +static const struct file_operations activity_stats_fops = { + .open = activity_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct notifier_block activity_stats_notifier_block = { + .notifier_call = activity_stats_notifier, +}; + +static int __init activity_stats_init(void) +{ + proc_create("activity", S_IRUGO, + init_net.proc_net_stat, &activity_stats_fops); + return register_pm_notifier(&activity_stats_notifier_block); +} + +subsys_initcall(activity_stats_init); + diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c index 71b6ab240dea26b228be35ba24ec3f43772f19f7..59ce1fcc220ce0a71fb57733be7cc91e6b8ac7fc 100644 --- a/net/caif/cfpkt_skbuff.c +++ b/net/caif/cfpkt_skbuff.c @@ -81,7 +81,11 @@ static struct cfpkt *cfpkt_create_pfx(u16 len, u16 pfx) { struct sk_buff *skb; - skb = alloc_skb(len + pfx, GFP_ATOMIC); + if (likely(in_interrupt())) + skb = alloc_skb(len + pfx, GFP_ATOMIC); + else + skb = alloc_skb(len + pfx, GFP_KERNEL); + if (unlikely(skb == NULL)) return NULL; diff --git a/net/core/dev.c b/net/core/dev.c index 1b7fb54d5d9a936a2f71aa031b443100052f66ec..50e77fe096f431bf776ff2652942a75709becd6c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1248,9 +1248,8 @@ int dev_set_alias(struct net_device *dev, const char *alias, size_t len) if (!new_ifalias) return -ENOMEM; dev->ifalias = new_ifalias; - memcpy(dev->ifalias, alias, len); - dev->ifalias[len] = 0; + strlcpy(dev->ifalias, alias, len+1); return len; } @@ -4383,12 +4382,6 @@ struct packet_offload *gro_find_complete_by_type(__be16 type) } EXPORT_SYMBOL(gro_find_complete_by_type); -static void napi_skb_free_stolen_head(struct sk_buff *skb) -{ - skb_dst_drop(skb); - kmem_cache_free(skbuff_head_cache, skb); -} - static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) { switch (ret) { @@ -4402,10 +4395,12 @@ static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) break; case GRO_MERGED_FREE: - if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) - napi_skb_free_stolen_head(skb); - else + if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) { + skb_dst_drop(skb); + kmem_cache_free(skbuff_head_cache, skb); + } else { __kfree_skb(skb); + } break; case GRO_HELD: @@ -4471,14 +4466,8 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, break; case GRO_DROP: - napi_reuse_skb(napi, skb); - break; - case GRO_MERGED_FREE: - if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) - napi_skb_free_stolen_head(skb); - else - napi_reuse_skb(napi, skb); + napi_reuse_skb(napi, skb); break; case GRO_MERGED: @@ -4571,13 +4560,8 @@ static void net_rps_send_ipi(struct softnet_data *remsd) while (remsd) { struct softnet_data *next = remsd->rps_ipi_next; - if (cpu_online(remsd->cpu)) { + if (cpu_online(remsd->cpu)) smp_call_function_single_async(remsd->cpu, &remsd->csd); - } else { - rps_lock(remsd); - remsd->backlog.state = 0; - rps_unlock(remsd); - } remsd = next; } #endif @@ -7098,8 +7082,8 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, } else { netdev_stats_to_stats64(storage, &dev->stats); } - storage->rx_dropped += (unsigned long)atomic_long_read(&dev->rx_dropped); - storage->tx_dropped += (unsigned long)atomic_long_read(&dev->tx_dropped); + storage->rx_dropped += atomic_long_read(&dev->rx_dropped); + storage->tx_dropped += atomic_long_read(&dev->tx_dropped); return storage; } EXPORT_SYMBOL(dev_get_stats); diff --git a/net/core/dst.c b/net/core/dst.c index e72d706f8d0c7f9e774e0d865d084c6460a4c1ae..d7ad628bf64e4c975ea60c86dc599b0126260d6e 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -462,20 +462,6 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, spin_lock_bh(&dst_garbage.lock); dst = dst_garbage.list; dst_garbage.list = NULL; - /* The code in dst_ifdown places a hold on the loopback device. - * If the gc entry processing is set to expire after a lengthy - * interval, this hold can cause netdev_wait_allrefs() to hang - * out and wait for a long time -- until the the loopback - * interface is released. If we're really unlucky, it'll emit - * pr_emerg messages to console too. Reset the interval here, - * so dst cleanups occur in a more timely fashion. - */ - if (dst_garbage.timer_inc > DST_GC_INC) { - dst_garbage.timer_inc = DST_GC_INC; - dst_garbage.timer_expires = DST_GC_MIN; - mod_delayed_work(system_wq, &dst_gc_work, - dst_garbage.timer_expires); - } spin_unlock_bh(&dst_garbage.lock); if (last) diff --git a/net/core/ethtool.c b/net/core/ethtool.c index b6bca625b0d2dca2ab586353f6aebdcad3ce7862..02fe0a88c391a5044169533cfa44b1a40a4b960f 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -930,11 +930,13 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr) static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) { - struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; + struct ethtool_wolinfo wol; if (!dev->ethtool_ops->get_wol) return -EOPNOTSUPP; + memset(&wol, 0, sizeof(struct ethtool_wolinfo)); + wol.cmd = ETHTOOL_GWOL; dev->ethtool_ops->get_wol(dev, &wol); if (copy_to_user(useraddr, &wol, sizeof(wol))) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2ec5324a7ff7ae1428830a939820c1827d6226cc..d43544ce7550814017dee25f631b3be18bcccb8a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -897,7 +897,6 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, + nla_total_size(1) /* IFLA_LINKMODE */ + nla_total_size(4) /* IFLA_CARRIER_CHANGES */ + nla_total_size(4) /* IFLA_LINK_NETNSID */ - + nla_total_size(4) /* IFLA_GROUP */ + nla_total_size(ext_filter_mask & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */ + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */ @@ -1090,8 +1089,6 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb, struct ifla_vf_mac vf_mac; struct ifla_vf_info ivi; - memset(&ivi, 0, sizeof(ivi)); - /* Not all SR-IOV capable drivers support the * spoofcheck and "RSS query enable" query. Preset to * -1 so the user space tool can detect that the driver @@ -1100,6 +1097,7 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb, ivi.spoofchk = -1; ivi.rss_query_en = -1; ivi.trusted = -1; + memset(ivi.mac, 0, sizeof(ivi.mac)); /* The default value for VF link state is "auto" * IFLA_VF_LINK_STATE_AUTO which equals zero */ @@ -1372,7 +1370,6 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_PHYS_SWITCH_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN }, [IFLA_LINK_NETNSID] = { .type = NLA_S32 }, [IFLA_PROTO_DOWN] = { .type = NLA_U8 }, - [IFLA_GROUP] = { .type = NLA_U32 }, }; static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 403593bd2b83b0d717f8062e476f8fffb50f92dc..b1dc096d22f8c83e771b1df68d7815661ac51bae 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -188,6 +188,12 @@ static inline void dnrt_free(struct dn_route *rt) call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free); } +static inline void dnrt_drop(struct dn_route *rt) +{ + dst_release(&rt->dst); + call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free); +} + static void dn_dst_check_expire(unsigned long dummy) { int i; @@ -242,7 +248,7 @@ static int dn_dst_gc(struct dst_ops *ops) } *rtp = rt->dst.dn_next; rt->dst.dn_next = NULL; - dnrt_free(rt); + dnrt_drop(rt); break; } spin_unlock_bh(&dn_rt_hash_table[i].lock); @@ -344,7 +350,7 @@ static int dn_insert_route(struct dn_route *rt, unsigned int hash, struct dn_rou dst_use(&rth->dst, now); spin_unlock_bh(&dn_rt_hash_table[hash].lock); - dst_free(&rt->dst); + dnrt_drop(rt); *rp = rth; return 0; } @@ -374,7 +380,7 @@ static void dn_run_flush(unsigned long dummy) for(; rt; rt = next) { next = rcu_dereference_raw(rt->dst.dn_next); RCU_INIT_POINTER(rt->dst.dn_next, NULL); - dnrt_free(rt); + dst_free((struct dst_entry *)rt); } nothing_to_declare: @@ -1181,7 +1187,7 @@ make_route: if (dev_out->flags & IFF_LOOPBACK) flags |= RTCF_LOCAL; - rt = dst_alloc(&dn_dst_ops, dev_out, 0, DST_OBSOLETE_NONE, DST_HOST); + rt = dst_alloc(&dn_dst_ops, dev_out, 1, DST_OBSOLETE_NONE, DST_HOST); if (rt == NULL) goto e_nobufs; diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index 29246bc9a7b4945ee850d493586c9adabc8a0ec3..85f2fdc360c27b21cb5b9c486e2d05ffb1d557d7 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -102,9 +102,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb) { struct nlmsghdr *nlh = nlmsg_hdr(skb); - if (skb->len < sizeof(*nlh) || - nlh->nlmsg_len < sizeof(*nlh) || - skb->len < nlh->nlmsg_len) + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) return; if (!netlink_capable(skb, CAP_NET_ADMIN)) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 554c2a961ad5663017281df477fa60380a2336b7..8dfe9fb7ad36728d91a2ae280c70f3a09878e893 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1006,8 +1006,10 @@ static int dsa_slave_phy_connect(struct dsa_slave_priv *p, /* Use already configured phy mode */ if (p->phy_interface == PHY_INTERFACE_MODE_NA) p->phy_interface = p->phy->interface; - return phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link, - p->phy_interface); + phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link, + p->phy_interface); + + return 0; } static int dsa_slave_phy_setup(struct dsa_slave_priv *p, diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 3809d523d012bc69f51a209797864b67ecb64c53..17adfdaf57957e42eec77abcbede42b83faf47db 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1102,7 +1102,6 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im) pmc = kzalloc(sizeof(*pmc), GFP_KERNEL); if (!pmc) return; - spin_lock_init(&pmc->lock); spin_lock_bh(&im->lock); pmc->interface = im->interface; in_dev_hold(in_dev); @@ -2027,26 +2026,21 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, static void ip_mc_clear_src(struct ip_mc_list *pmc) { - struct ip_sf_list *psf, *nextpsf, *tomb, *sources; + struct ip_sf_list *psf, *nextpsf; - spin_lock_bh(&pmc->lock); - tomb = pmc->tomb; - pmc->tomb = NULL; - sources = pmc->sources; - pmc->sources = NULL; - pmc->sfmode = MCAST_EXCLUDE; - pmc->sfcount[MCAST_INCLUDE] = 0; - pmc->sfcount[MCAST_EXCLUDE] = 1; - spin_unlock_bh(&pmc->lock); - - for (psf = tomb; psf; psf = nextpsf) { + for (psf = pmc->tomb; psf; psf = nextpsf) { nextpsf = psf->sf_next; kfree(psf); } - for (psf = sources; psf; psf = nextpsf) { + pmc->tomb = NULL; + for (psf = pmc->sources; psf; psf = nextpsf) { nextpsf = psf->sf_next; kfree(psf); } + pmc->sources = NULL; + pmc->sfmode = MCAST_EXCLUDE; + pmc->sfcount[MCAST_INCLUDE] = 0; + pmc->sfcount[MCAST_EXCLUDE] = 1; } /* Join a multicast group diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index ccc5980797fcdb9ed3a1003db47e4e8cb7180279..54cf0f2251168b85a1c4bc03b3929ed30dbd9e04 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -12,6 +12,11 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -109,12 +114,14 @@ static void __inet_put_port(struct sock *sk) struct inet_bind_bucket *tb; spin_lock(&head->lock); - tb = inet_csk(sk)->icsk_bind_hash; - __sk_del_bind_node(sk); - tb->num_owners--; - inet_csk(sk)->icsk_bind_hash = NULL; - inet_sk(sk)->inet_num = 0; - inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); + if (inet_csk(sk)->icsk_bind_hash) { + tb = inet_csk(sk)->icsk_bind_hash; + __sk_del_bind_node(sk); + tb->num_owners--; + inet_csk(sk)->icsk_bind_hash = NULL; + inet_sk(sk)->inet_num = 0; + inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); + } spin_unlock(&head->lock); } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9bdd7847ef3ab1a57642ca29a8411c0d4669b20d..9a764ae2de843f4a327018f26d984aaea4710193 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -244,6 +244,11 @@ * * TCP_CLOSE socket is finished */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "TCP: " fmt @@ -269,6 +274,7 @@ #include #include #include +#include #include #include @@ -1299,6 +1305,10 @@ out: tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); out_nopush: release_sock(sk); + + if (copied + copied_syn) + uid_stat_tcp_snd(from_kuid(&init_user_ns, current_uid()), + copied + copied_syn); return copied + copied_syn; do_fault: @@ -1576,6 +1586,8 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, if (copied > 0) { tcp_recv_skb(sk, seq, &offset); tcp_cleanup_rbuf(sk, copied); + uid_stat_tcp_rcv(from_kuid(&init_user_ns, current_uid()), + copied); } return copied; } @@ -1909,6 +1921,10 @@ skip_copy: tcp_cleanup_rbuf(sk, copied); release_sock(sk); + + if (copied > 0) + uid_stat_tcp_rcv(from_kuid(&init_user_ns, current_uid()), + copied); return copied; out: @@ -1917,6 +1933,9 @@ out: recv_urg: err = tcp_recv_urg(sk, msg, len, flags); + if (err > 0) + uid_stat_tcp_rcv(from_kuid(&init_user_ns, current_uid()), + err); goto out; recv_sndq: @@ -2272,8 +2291,6 @@ int tcp_disconnect(struct sock *sk, int flags) tcp_init_send_head(sk); memset(&tp->rx_opt, 0, sizeof(tp->rx_opt)); __sk_dst_reset(sk); - dst_release(sk->sk_rx_dst); - sk->sk_rx_dst = NULL; tcp_saved_syn_free(tp); WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 69d52fee247ed1c2efc989faf5e4ce73c2acf5b8..710101376a760ad218dd136d5c849cb5f9f4e87a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2166,7 +2166,8 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; - int cnt, oldcnt, lost; + int cnt, oldcnt; + int err; unsigned int mss; /* Use SACK to deduce losses of new sequences sent during recovery */ const u32 loss_high = tcp_is_sack(tp) ? tp->snd_nxt : tp->high_seq; @@ -2206,10 +2207,9 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head) break; mss = tcp_skb_mss(skb); - /* If needed, chop off the prefix to mark as lost. */ - lost = (packets - oldcnt) * mss; - if (lost < skb->len && - tcp_fragment(sk, skb, lost, mss, GFP_ATOMIC) < 0) + err = tcp_fragment(sk, skb, (packets - oldcnt) * mss, + mss, GFP_ATOMIC); + if (err < 0) break; cnt = packets; } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4b707ad4ffbdc7a85327316349d3ecd7b308375a..4fe0359d8abf4da11058fe11cc40a74d4325d978 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -320,9 +320,9 @@ static void addrconf_mod_rs_timer(struct inet6_dev *idev, static void addrconf_mod_dad_work(struct inet6_ifaddr *ifp, unsigned long delay) { - in6_ifa_hold(ifp); - if (mod_delayed_work(addrconf_wq, &ifp->dad_work, delay)) - in6_ifa_put(ifp); + if (!delayed_work_pending(&ifp->dad_work)) + in6_ifa_hold(ifp); + mod_delayed_work(addrconf_wq, &ifp->dad_work, delay); } static int snmp6_alloc_dev(struct inet6_dev *idev) @@ -1801,7 +1801,17 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) { - if (ifp->flags&IFA_F_TEMPORARY) { + if (ifp->flags&IFA_F_PERMANENT) { + spin_lock_bh(&ifp->lock); + addrconf_del_dad_work(ifp); + ifp->flags |= IFA_F_TENTATIVE; + if (dad_failed) + ifp->flags |= IFA_F_DADFAILED; + spin_unlock_bh(&ifp->lock); + if (dad_failed) + ipv6_ifa_notify(0, ifp); + in6_ifa_put(ifp); + } else if (ifp->flags&IFA_F_TEMPORARY) { struct inet6_ifaddr *ifpub; spin_lock_bh(&ifp->lock); ifpub = ifp->ifpub; @@ -1814,16 +1824,6 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) spin_unlock_bh(&ifp->lock); } ipv6_del_addr(ifp); - } else if (ifp->flags&IFA_F_PERMANENT || !dad_failed) { - spin_lock_bh(&ifp->lock); - addrconf_del_dad_work(ifp); - ifp->flags |= IFA_F_TENTATIVE; - if (dad_failed) - ifp->flags |= IFA_F_DADFAILED; - spin_unlock_bh(&ifp->lock); - if (dad_failed) - ipv6_ifa_notify(0, ifp); - in6_ifa_put(ifp); } else { ipv6_del_addr(ifp); } @@ -3212,7 +3212,6 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, { struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct inet6_dev *idev = __in6_dev_get(dev); - struct net *net = dev_net(dev); int run_pending = 0; int err; @@ -3228,7 +3227,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, case NETDEV_CHANGEMTU: /* if MTU under IPV6_MIN_MTU stop IPv6 on this interface. */ if (dev->mtu < IPV6_MIN_MTU) { - addrconf_ifdown(dev, dev != net->loopback_dev); + addrconf_ifdown(dev, 1); break; } @@ -3341,7 +3340,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, * IPV6_MIN_MTU stop IPv6 on this interface. */ if (dev->mtu < IPV6_MIN_MTU) - addrconf_ifdown(dev, dev != net->loopback_dev); + addrconf_ifdown(dev, 1); } break; diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index d7c1ee7cf0e28089f0a42a31029c85aa69c74edc..27796c33ca05e65894d59687f31f71936214c513 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -184,11 +184,6 @@ ipv4_connected: err = 0; if (IS_ERR(dst)) { err = PTR_ERR(dst); - /* Reset daddr and dport so that udp_v6_early_demux() - * fails to find this socket - */ - memset(&sk->sk_v6_daddr, 0, sizeof(sk->sk_v6_daddr)); - inet->inet_dport = 0; goto out; } diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 9ac4f0cef27d01c8ad3b1db7d91958b98f7e5cc6..ed33abf57abd7d7ec71685a7180cf88ec132626c 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -32,6 +32,7 @@ struct fib6_rule { struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, int flags, pol_lookup_t lookup) { + struct rt6_info *rt; struct fib_lookup_arg arg = { .lookup_ptr = lookup, .flags = FIB_LOOKUP_NOREF, @@ -40,11 +41,21 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, fib_rules_lookup(net->ipv6.fib6_rules_ops, flowi6_to_flowi(fl6), flags, &arg); - if (arg.result) - return arg.result; + rt = arg.result; - dst_hold(&net->ipv6.ip6_null_entry->dst); - return &net->ipv6.ip6_null_entry->dst; + if (!rt) { + dst_hold(&net->ipv6.ip6_null_entry->dst); + return &net->ipv6.ip6_null_entry->dst; + } + + if (rt->rt6i_flags & RTF_REJECT && + rt->dst.error == -EAGAIN) { + ip6_rt_put(rt); + rt = net->ipv6.ip6_null_entry; + dst_hold(&rt->dst); + } + + return &rt->dst; } static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, @@ -105,8 +116,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, flp6->saddr = saddr; } err = rt->dst.error; - if (err != -EAGAIN) - goto out; + goto out; } again: ip6_rt_put(rt); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index f60e8caea7677c3b6ad05f9623006dfc1e43d7cc..85bf864587067048c55579718e4db263e4cb292a 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -290,7 +290,8 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, struct rt6_info *rt; rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, flags); - if (rt->dst.error == -EAGAIN) { + if (rt->rt6i_flags & RTF_REJECT && + rt->dst.error == -EAGAIN) { ip6_rt_put(rt); rt = net->ipv6.ip6_null_entry; dst_hold(&rt->dst); @@ -767,7 +768,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, goto next_iter; } - if (rt6_duplicate_nexthop(iter, rt)) { + if (iter->dst.dev == rt->dst.dev && + iter->rt6i_idev == rt->rt6i_idev && + ipv6_addr_equal(&iter->rt6i_gateway, + &rt->rt6i_gateway)) { if (rt->rt6i_nsiblings) rt->rt6i_nsiblings = 0; if (!(iter->rt6i_flags & RTF_EXPIRES)) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 72b53b83a720056810a6f396dba50381301bfc42..d7c4677d8a750256f2cfe15c098c391359475b68 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -25,6 +25,11 @@ * : add ip6_append_data and related functions * for datagram xmit */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -1003,11 +1008,6 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk, } } #endif - if (ipv6_addr_v4mapped(&fl6->saddr) && - !(ipv6_addr_v4mapped(&fl6->daddr) || ipv6_addr_any(&fl6->daddr))) { - err = -EAFNOSUPPORT; - goto out_err_release; - } return 0; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index dd37fe0b6a49846be7cfad0582d873fa114fbb71..e98613d2f34f9bdb5125587f7cf5efec327c1151 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2822,11 +2822,17 @@ static int ip6_route_info_append(struct list_head *rt6_nh_list, struct rt6_info *rt, struct fib6_config *r_cfg) { struct rt6_nh *nh; + struct rt6_info *rtnh; int err = -EEXIST; list_for_each_entry(nh, rt6_nh_list, next) { /* check if rt6_info already exists */ - if (rt6_duplicate_nexthop(nh->rt6_info, rt)) + rtnh = nh->rt6_info; + + if (rtnh->dst.dev == rt->dst.dev && + rtnh->rt6i_idev == rt->rt6i_idev && + ipv6_addr_equal(&rtnh->rt6i_gateway, + &rt->rt6i_gateway)) return err; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 329ae3ccfa35df8587aa4ff433422c8345540673..8a07c63ddccd3b5da18b7b53823d7f88450e97ec 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include @@ -965,22 +964,15 @@ static struct sock *__udp6_lib_demux_lookup(struct net *net, int dif) { struct sock *sk; - struct hlist_nulls_node *hnode; - unsigned short hnum = ntohs(loc_port); - unsigned int hash2 = udp6_portaddr_hash(net, loc_addr, hnum); - unsigned int slot2 = hash2 & udp_table.mask; - struct udp_hslot *hslot2 = &udp_table.hash2[slot2]; - const __portpair ports = INET_COMBINED_PORTS(rmt_port, hnum); + rcu_read_lock(); + sk = __udp6_lib_lookup(net, rmt_addr, rmt_port, loc_addr, loc_port, + dif, &udp_table); + if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) + sk = NULL; + rcu_read_unlock(); - udp_portaddr_for_each_entry_rcu(sk, hnode, &hslot2->head) { - if (sk->sk_state == TCP_ESTABLISHED && - INET6_MATCH(sk, net, rmt_addr, loc_addr, ports, dif)) - return sk; - /* Only check first socket in chain */ - break; - } - return NULL; + return sk; } static void udp_v6_early_demux(struct sk_buff *skb) @@ -1005,7 +997,7 @@ static void udp_v6_early_demux(struct sk_buff *skb) else return; - if (!sk || !atomic_inc_not_zero_hint(&sk->sk_refcnt, 2)) + if (!sk) return; skb->sk = sk; @@ -1073,7 +1065,6 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, */ offset = skb_transport_offset(skb); skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); - csum = skb->csum; skb->ip_summed = CHECKSUM_NONE; diff --git a/net/key/af_key.c b/net/key/af_key.c index e67c28e614b9c41fe93c96f9a9dcd452f64555a8..f9c9ecb0cdd3b3eea618538fda2e884583f9bc09 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1135,7 +1135,6 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, goto out; } - err = -ENOBUFS; key = ext_hdrs[SADB_EXT_KEY_AUTH - 1]; if (sa->sadb_sa_auth) { int keysize = 0; @@ -1147,10 +1146,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, if (key) keysize = (key->sadb_key_bits + 7) / 8; x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL); - if (!x->aalg) { - err = -ENOMEM; + if (!x->aalg) goto out; - } strcpy(x->aalg->alg_name, a->name); x->aalg->alg_key_len = 0; if (key) { @@ -1169,10 +1166,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, goto out; } x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL); - if (!x->calg) { - err = -ENOMEM; + if (!x->calg) goto out; - } strcpy(x->calg->alg_name, a->name); x->props.calgo = sa->sadb_sa_encrypt; } else { @@ -1186,10 +1181,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, if (key) keysize = (key->sadb_key_bits + 7) / 8; x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL); - if (!x->ealg) { - err = -ENOMEM; + if (!x->ealg) goto out; - } strcpy(x->ealg->alg_name, a->name); x->ealg->alg_key_len = 0; if (key) { @@ -1234,10 +1227,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, struct xfrm_encap_tmpl *natt; x->encap = kmalloc(sizeof(*x->encap), GFP_KERNEL); - if (!x->encap) { - err = -ENOMEM; + if (!x->encap) goto out; - } natt = x->encap; n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2ee53dc1ddf71166fd80fdfa11ce6c39ae15fb89..175ffcf7fb06bfb5c9c1f95e2c17f42d666ee26f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -891,17 +891,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) supp_ht = supp_ht || sband->ht_cap.ht_supported; supp_vht = supp_vht || sband->vht_cap.vht_supported; - if (!sband->ht_cap.ht_supported) - continue; + if (sband->ht_cap.ht_supported) + local->rx_chains = + max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs), + local->rx_chains); /* TODO: consider VHT for RX chains, hopefully it's the same */ - local->rx_chains = - max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs), - local->rx_chains); - - /* no need to mask, SM_PS_DISABLED has all bits set */ - sband->ht_cap.cap |= WLAN_HT_CAP_SM_PS_DISABLED << - IEEE80211_HT_CAP_SM_PS_SHIFT; } /* if low-level driver supports AP, we also support VLAN */ diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index e565b2becb147f96e7918ab511d3d782cd5eda0c..9f5272968abb095cb3e758b3906cb6dcbd86ab24 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -45,8 +45,6 @@ #include #include #include -#include -#include #ifdef CONFIG_NF_NAT_NEEDED #include #include @@ -1800,8 +1798,6 @@ ctnetlink_create_conntrack(struct net *net, nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC); nf_ct_labels_ext_add(ct); - nfct_seqadj_ext_add(ct); - nfct_synproxy_ext_add(ct); /* we must add conntrack extensions before confirmation. */ ct->status |= IPS_CONFIRMED; diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 00f798b20b20b79478fc9b2380820774028a33ed..b7c43def0dc69e1cd03db238e0174283d895003a 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -104,7 +104,7 @@ tcpmss_mangle_packet(struct sk_buff *skb, tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); tcp_hdrlen = tcph->doff * 4; - if (len < tcp_hdrlen || tcp_hdrlen < sizeof(struct tcphdr)) + if (len < tcp_hdrlen) return -1; if (info->mss == XT_TCPMSS_CLAMP_PMTU) { @@ -156,10 +156,6 @@ tcpmss_mangle_packet(struct sk_buff *skb, if (len > tcp_hdrlen) return 0; - /* tcph->doff has 4 bits, do not wrap it to 0 */ - if (tcp_hdrlen >= 15 * 4) - return 0; - /* * MSS Option not found ?! add it.. */ diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c index 94663440d160e0eddc25d8c3755c9c193812c83f..c1603a4b27921885a268e860382726b37717fe15 100644 --- a/net/netfilter/xt_quota2.c +++ b/net/netfilter/xt_quota2.c @@ -11,6 +11,11 @@ * it under the terms of the GNU General Public License; either * version 2 of the License, as published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -296,7 +301,7 @@ quota_mt2(const struct sk_buff *skb, struct xt_action_param *par) } ret = true; } else { - if (e->quota >= skb->len) { + if (e->quota > skb->len) { if (!(q->flags & XT_QUOTA_NO_CHANGE)) e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len; ret = !ret; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 2b0f0ac498d2c02c92a62d8e749a103f5b1849c1..5fdef25b40566d4fe9490e41e857c6645671de33 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -14,6 +14,11 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2012 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "hci: %s: " fmt, __func__ diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c index 1fe725d660852bb2422c94d37cc566e793a18464..0487e94a0bb7fb664dd9e16f4f3f9c796647086b 100644 --- a/net/nfc/hci/hcp.c +++ b/net/nfc/hci/hcp.c @@ -14,6 +14,11 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2012 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define pr_fmt(fmt) "hci: %s: " fmt, __func__ diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c index e353e32552064786e4f67b3368d20aebffda6765..0936a4a32b476fdde5c7208fc465ec3324bbcf09 100644 --- a/net/rds/tcp_listen.c +++ b/net/rds/tcp_listen.c @@ -78,7 +78,7 @@ int rds_tcp_accept_one(struct socket *sock) struct inet_sock *inet; struct rds_tcp_connection *rs_tcp; - ret = sock_create_lite(sock->sk->sk_family, + ret = sock_create_kern(sock_net(sock->sk), sock->sk->sk_family, sock->sk->sk_type, sock->sk->sk_protocol, &new_sock); if (ret) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 71e1f0def5a51b6ab5be270e9f75732844f8a994..7108d0891882deb0112e7660331b9ea8ec341bb5 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -16,6 +16,11 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2012 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c index b17556c346ce7c7c98d44e11dde9107a16d1cbe5..ae60f35b363df724245dec1d529cc908ed8f85b1 100644 --- a/net/rmnet_data/rmnet_data_handlers.c +++ b/net/rmnet_data/rmnet_data_handlers.c @@ -476,12 +476,10 @@ static rx_handler_result_t _rmnet_map_ingress_handler(struct sk_buff *skb, if (likely((ckresult == RMNET_MAP_CHECKSUM_OK) || (ckresult == RMNET_MAP_CHECKSUM_SKIPPED))) skb->ip_summed |= CHECKSUM_UNNECESSARY; - else if (ckresult != - RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION && - ckresult != RMNET_MAP_CHECKSUM_VALIDATION_FAILED && - ckresult != RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT && - ckresult != RMNET_MAP_CHECKSUM_VALID_FLAG_NOT_SET && - ckresult != RMNET_MAP_CHECKSUM_FRAGMENTED_PACKET) { + else if (ckresult != RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION + && ckresult != RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT + && ckresult != RMNET_MAP_CHECKSUM_VALID_FLAG_NOT_SET + && ckresult != RMNET_MAP_CHECKSUM_FRAGMENTED_PACKET) { rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM); return RX_HANDLER_CONSUMED; diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 91d43ab3a9610fbb0fc45fb4afcf5ff7ff9f098f..da3cc09f683e982a43269d166acfad0e05575020 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c @@ -215,7 +215,7 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ, unsigned int *_toklen) { const __be32 *xdr = *_xdr; - unsigned int toklen = *_toklen, n_parts, loop, tmp, paddedlen; + unsigned int toklen = *_toklen, n_parts, loop, tmp; /* there must be at least one name, and at least #names+1 length * words */ @@ -245,16 +245,16 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ, toklen -= 4; if (tmp <= 0 || tmp > AFSTOKEN_STRING_MAX) return -EINVAL; - paddedlen = (tmp + 3) & ~3; - if (paddedlen > toklen) + if (tmp > toklen) return -EINVAL; princ->name_parts[loop] = kmalloc(tmp + 1, GFP_KERNEL); if (!princ->name_parts[loop]) return -ENOMEM; memcpy(princ->name_parts[loop], xdr, tmp); princ->name_parts[loop][tmp] = 0; - toklen -= paddedlen; - xdr += paddedlen >> 2; + tmp = (tmp + 3) & ~3; + toklen -= tmp; + xdr += tmp >> 2; } if (toklen < 4) @@ -263,16 +263,16 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ, toklen -= 4; if (tmp <= 0 || tmp > AFSTOKEN_K5_REALM_MAX) return -EINVAL; - paddedlen = (tmp + 3) & ~3; - if (paddedlen > toklen) + if (tmp > toklen) return -EINVAL; princ->realm = kmalloc(tmp + 1, GFP_KERNEL); if (!princ->realm) return -ENOMEM; memcpy(princ->realm, xdr, tmp); princ->realm[tmp] = 0; - toklen -= paddedlen; - xdr += paddedlen >> 2; + tmp = (tmp + 3) & ~3; + toklen -= tmp; + xdr += tmp >> 2; _debug("%s/...@%s", princ->name_parts[0], princ->realm); @@ -291,7 +291,7 @@ static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td, unsigned int *_toklen) { const __be32 *xdr = *_xdr; - unsigned int toklen = *_toklen, len, paddedlen; + unsigned int toklen = *_toklen, len; /* there must be at least one tag and one length word */ if (toklen <= 8) @@ -305,17 +305,15 @@ static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td, toklen -= 8; if (len > max_data_size) return -EINVAL; - paddedlen = (len + 3) & ~3; - if (paddedlen > toklen) - return -EINVAL; td->data_len = len; if (len > 0) { td->data = kmemdup(xdr, len, GFP_KERNEL); if (!td->data) return -ENOMEM; - toklen -= paddedlen; - xdr += paddedlen >> 2; + len = (len + 3) & ~3; + toklen -= len; + xdr += len >> 2; } _debug("tag %x len %x", td->tag, td->data_len); @@ -387,7 +385,7 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, const __be32 **_xdr, unsigned int *_toklen) { const __be32 *xdr = *_xdr; - unsigned int toklen = *_toklen, len, paddedlen; + unsigned int toklen = *_toklen, len; /* there must be at least one length word */ if (toklen <= 4) @@ -399,9 +397,6 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, toklen -= 4; if (len > AFSTOKEN_K5_TIX_MAX) return -EINVAL; - paddedlen = (len + 3) & ~3; - if (paddedlen > toklen) - return -EINVAL; *_tktlen = len; _debug("ticket len %u", len); @@ -410,8 +405,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, *_ticket = kmemdup(xdr, len, GFP_KERNEL); if (!*_ticket) return -ENOMEM; - toklen -= paddedlen; - xdr += paddedlen >> 2; + len = (len + 3) & ~3; + toklen -= len; + xdr += len >> 2; } *_xdr = xdr; @@ -554,7 +550,7 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep) { const __be32 *xdr = prep->data, *token; const char *cp; - unsigned int len, paddedlen, loop, ntoken, toklen, sec_ix; + unsigned int len, tmp, loop, ntoken, toklen, sec_ix; size_t datalen = prep->datalen; int ret; @@ -580,21 +576,22 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep) if (len < 1 || len > AFSTOKEN_CELL_MAX) goto not_xdr; datalen -= 4; - paddedlen = (len + 3) & ~3; - if (paddedlen > datalen) + tmp = (len + 3) & ~3; + if (tmp > datalen) goto not_xdr; cp = (const char *) xdr; for (loop = 0; loop < len; loop++) if (!isprint(cp[loop])) goto not_xdr; - for (; loop < paddedlen; loop++) - if (cp[loop]) - goto not_xdr; + if (len < tmp) + for (; loop < tmp; loop++) + if (cp[loop]) + goto not_xdr; _debug("cellname: [%u/%u] '%*.*s'", - len, paddedlen, len, len, (const char *) xdr); - datalen -= paddedlen; - xdr += paddedlen >> 2; + len, tmp, len, len, (const char *) xdr); + datalen -= tmp; + xdr += tmp >> 2; /* get the token count */ if (datalen < 12) @@ -615,11 +612,10 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep) sec_ix = ntohl(*xdr); datalen -= 4; _debug("token: [%x/%zx] %x", toklen, datalen, sec_ix); - paddedlen = (toklen + 3) & ~3; - if (toklen < 20 || toklen > datalen || paddedlen > datalen) + if (toklen < 20 || toklen > datalen) goto not_xdr; - datalen -= paddedlen; - xdr += paddedlen >> 2; + datalen -= (toklen + 3) & ~3; + xdr += (toklen + 3) >> 2; } while (--loop > 0); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index ca4ecc2463475d89fbec8656739364ae37825a92..5474dc7c125a9acb5a709cfb8dcf9776ce99ac63 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1004,9 +1004,6 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, return sch; } - /* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */ - if (ops->destroy) - ops->destroy(sch); err_out3: dev_put(dev); kfree((char *) sch - sch->padded); diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index 45d4b2f22f62ee8174d4d5159002c69ad9684532..13d6f83ec4913f6eb8cdefa1bf3c363792c0a510 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -636,9 +636,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt) q->hhf_arrays[i] = hhf_zalloc(HHF_ARRAYS_LEN * sizeof(u32)); if (!q->hhf_arrays[i]) { - /* Note: hhf_destroy() will be called - * by our caller. - */ + hhf_destroy(sch); return -ENOMEM; } } @@ -649,9 +647,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt) q->hhf_valid_bits[i] = hhf_zalloc(HHF_ARRAYS_LEN / BITS_PER_BYTE); if (!q->hhf_valid_bits[i]) { - /* Note: hhf_destroy() will be called - * by our caller. - */ + hhf_destroy(sch); return -ENOMEM; } } diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index d9c84328e7ebb2c01b6d266a3843ab24ce8beb80..3e82f047caaf40461c9f408bd0572a64147e1a8f 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -52,7 +52,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt) /* pre-allocate qdiscs, attachment can't fail */ priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]), GFP_KERNEL); - if (!priv->qdiscs) + if (priv->qdiscs == NULL) return -ENOMEM; for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { @@ -60,14 +60,18 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt) qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, TC_H_MAKE(TC_H_MAJ(sch->handle), TC_H_MIN(ntx + 1))); - if (!qdisc) - return -ENOMEM; + if (qdisc == NULL) + goto err; priv->qdiscs[ntx] = qdisc; qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; } sch->flags |= TCQ_F_MQROOT; return 0; + +err: + mq_destroy(sch); + return -ENOMEM; } static void mq_attach(struct Qdisc *sch) diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index 66bccc5ff4ea962e601ada91b5a76d9979d8fb78..ad70ecf57ce793d7b50b50e9220c24fa4ab30ab5 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c @@ -117,17 +117,20 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) /* pre-allocate qdisc, attachment can't fail */ priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]), GFP_KERNEL); - if (!priv->qdiscs) - return -ENOMEM; + if (priv->qdiscs == NULL) { + err = -ENOMEM; + goto err; + } for (i = 0; i < dev->num_tx_queues; i++) { dev_queue = netdev_get_tx_queue(dev, i); qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, TC_H_MAKE(TC_H_MAJ(sch->handle), TC_H_MIN(i + 1))); - if (!qdisc) - return -ENOMEM; - + if (qdisc == NULL) { + err = -ENOMEM; + goto err; + } priv->qdiscs[i] = qdisc; qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; } @@ -140,7 +143,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) priv->hw_owned = 1; err = dev->netdev_ops->ndo_setup_tc(dev, qopt->num_tc); if (err) - return err; + goto err; } else { netdev_set_num_tc(dev, qopt->num_tc); for (i = 0; i < qopt->num_tc; i++) @@ -154,6 +157,10 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) sch->flags |= TCQ_F_MQROOT; return 0; + +err: + mqprio_destroy(sch); + return err; } static void mqprio_attach(struct Qdisc *sch) diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 4431e2833e459ae61f38b1f60bcbd1914fdaee89..498f0a2cb47fca72bf504a712fdc8742cc947a1d 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -742,10 +742,9 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt) q->ht = sfq_alloc(sizeof(q->ht[0]) * q->divisor); q->slots = sfq_alloc(sizeof(q->slots[0]) * q->maxflows); if (!q->ht || !q->slots) { - /* Note: sfq_destroy() will be called by our caller */ + sfq_destroy(sch); return -ENOMEM; } - for (i = 0; i < q->divisor; i++) q->ht[i] = SFQ_EMPTY_SLOT; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 3ebf3b652d600d75719468018ee8fbfc25114b27..956141b716195bf38fd3cbb23d58c2f224aa674a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -239,7 +239,7 @@ static struct sctp_transport *sctp_addr_id2transport(struct sock *sk, union sctp_addr *laddr = (union sctp_addr *)addr; struct sctp_transport *transport; - if (!af || sctp_verify_addr(sk, laddr, af->sockaddr_len)) + if (sctp_verify_addr(sk, laddr, af->sockaddr_len)) return NULL; addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep, diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index decd8b8d751fa89903285d5f0822bb6e9a3fced5..1f5d18d80fbad6d796d4e9f3477809e3fffd2ab4 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -997,8 +997,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct path path = { NULL, NULL }; err = -EINVAL; - if (addr_len < offsetofend(struct sockaddr_un, sun_family) || - sunaddr->sun_family != AF_UNIX) + if (sunaddr->sun_family != AF_UNIX) goto out; if (addr_len == sizeof(short)) { @@ -1109,10 +1108,6 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, unsigned int hash; int err; - err = -EINVAL; - if (alen < offsetofend(struct sockaddr, sa_family)) - goto out; - if (addr->sa_family != AF_UNSPEC) { err = unix_mkname(sunaddr, alen, &hash); if (err < 0) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 0727a6e9f7800e83a10672c168856839dcef5c7c..17e3321afa0be6562a7d3a366060c8fc809ad707 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -1,1398 +1,338 @@ # This is the world regulatory domain country 00: - (2402 - 2472 @ 40), (20) + (2402 - 2472 @ 20), (20) # Channel 12 - 13. - (2457 - 2482 @ 40), (20), PASSIVE-SCAN, NO-IBSS - # Channel 14. Only JP enables this and for 802.11b only - (2474 - 2494 @ 20), (20), PASSIVE-SCAN, NO-IBSS, NO-OFDM + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS # Channel 36 - 48 (5170 - 5250 @ 80), (20), PASSIVE-SCAN, NO-IBSS - (5250 - 5330 @ 80), (20), PASSIVE-SCAN, NO-IBSS - (5490 - 5710 @ 80), (20), PASSIVE-SCAN, NO-IBSS + (5250 - 5330 @ 80), (20), PASSIVE-SCAN, DFS, NO-IBSS + (5490 - 5730 @ 80), (20), PASSIVE-SCAN, DFS, NO-IBSS # NB: 5260 MHz - 5700 MHz requies DFS # Channel 149 - 165 - (5735 - 5835 @ 80), (20), PASSIVE-SCAN, NO-IBSS - # IEEE 802.11ad (60GHz), channels 1..3 - (57240 - 63720 @ 2160), (0) - - -country AE: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country AF: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country AI: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country AL: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5150 - 5250 @ 80), (23), AUTO-BW - (5250 - 5350 @ 80), (23), DFS, AUTO-BW - (5470 - 5710 @ 160), (30), DFS - -country AM: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 20), (18) - (5250 - 5330 @ 20), (18), DFS + (5735 - 5835 @ 80), (14), PASSIVE-SCAN, NO-IBSS -country AN: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country AR: - (2402 - 2482 @ 40), (36) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (36), AUTO-BW - (5490 - 5590 @ 80), (36) - (5650 - 5730 @ 80), (36) - (5735 - 5835 @ 80), (36) - # 60 gHz band channels 1-3 - (57240 - 63720 @ 2160), (40), NO-OUTDOOR - -country AS: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5850 @ 80), (30) - -country AT: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) +country AE: DFS-FCC + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (23), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN + +country AR: DFS-FCC + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (17), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5590 @ 80), (24), PASSIVE-SCAN, DFS + (5650 - 5710 @ 40), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN country AU: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5590 @ 80), (24), DFS - (5650 - 5730 @ 80), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 - (57240 - 65880 @ 2160), (43), NO-OUTDOOR - -country AW: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country AZ: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (18), AUTO-BW - (5250 - 5330 @ 80), (18), DFS, AUTO-BW - -country BA: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country BB: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5735 - 5835 @ 80), (30) - -country BD: - (2402 - 2482 @ 40), (20) - (5735 - 5835 @ 80), (30) - -country BE: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country BF: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country BG: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country BH: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 20), (23) - (5735 - 5835 @ 20), (33) - -country BL: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country BM: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country BN: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5735 - 5835 @ 80), (20) - -country BO: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5250 - 5330 @ 80), (30), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5590 @ 80), (23), PASSIVE-SCAN, DFS + (5650 - 5710 @ 40), (23), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (14), PASSIVE-SCAN + +country BH: DFS-ETSI + (2402 - 2482 @ 20), (20) + (5170 - 5250 @ 20), (20), PASSIVE-SCAN + (5250 - 5330 @ 20), (20), PASSIVE-SCAN, DFS + (5735 - 5835 @ 20), (20), PASSIVE-SCAN country BR: DFS-FCC - (2402 - 2482 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3 - (57240 - 63720 @ 2160), (40) - -country BS: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country BT: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country BY: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country BZ: - (2402 - 2482 @ 40), (36) - (5170 - 5330 @ 160), (27) - (5490 - 5730 @ 160), (36) - (5735 - 5835 @ 80), (36) + (2402 - 2472 @ 20), (30) + # Channel 12 - 13. + (2457 - 2482 @ 20), (30), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (24), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN country CA: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5590 @ 80), (24), DFS - (5650 - 5730 @ 80), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3 - (57240 - 63720 @ 2160), (40) - -country CF: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 40), (24) - (5250 - 5330 @ 40), (24), DFS - (5490 - 5730 @ 40), (24), DFS - (5735 - 5835 @ 40), (30) - -country CH: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country CI: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country CL: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (20) - (5735 - 5835 @ 80), (20) - # 60 gHz band channels 1-3 - (57240 - 63720 @ 2160), (50), NO-OUTDOOR + (2402 - 2472 @ 20), (30) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5590 @ 80), (23), PASSIVE-SCAN, DFS + (5650 - 5710 @ 40), (23), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN + +country CL: DFS-ETSI + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (20), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (20), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 80), (20), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (20), PASSIVE-SCAN country CN: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5735 - 5835 @ 80), (33) - # 60 gHz band channels 2,3: 44dBm - (59400 - 63720 @ 2160), (44) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5735 - 5835 @ 80), (27), PASSIVE-SCAN country CO: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country CR: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 20), (24) - (5250 - 5330 @ 20), (24), DFS - (5490 - 5730 @ 20), (24), DFS - (5735 - 5835 @ 20), (30) - # 60 gHz band channels 1-3 - (57240 - 63720 @ 2160), (30) - -country CX: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country CY: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -# Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf -# and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf -country CZ: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -# Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from -# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf -# For the 5GHz range also see -# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38216/publicationFile/6579/WLAN5GHzVfg7_2010_28042010pdf.pdf - -country DE: DFS-ETSI - # entries 279004 and 280006 - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country DK: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country DM: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5735 - 5835 @ 80), (30) - -country DO: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5735 - 5835 @ 80), (30) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (17), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), PASSIVE-SCAN, (30) country DZ: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5670 @ 160), (23), DFS + (2402 - 2482 @ 20), (20) + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5670 @ 160), (23), PASSIVE-SCAN, DFS country EC: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 20), (24) - (5250 - 5330 @ 20), (24), DFS - (5490 - 5730 @ 20), (24), DFS + (2402 - 2482 @ 20), (20) + (5170 - 5250 @ 20), (17), PASSIVE-SCAN + (5250 - 5330 @ 20), (24), PASSIVE-SCAN, DFS + (5490 - 5710 @ 20), (24), PASSIVE-SCAN, DFS (5735 - 5835 @ 20), (30) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) - -country EE: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) country EG: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 40), (23) - (5250 - 5330 @ 40), (23), DFS - -country ES: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country ET: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country FI: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country FM: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country FR: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country GB: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country GD: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country GE: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (18), AUTO-BW - (5250 - 5330 @ 80), (18), DFS, AUTO-BW - -country GF: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country GH: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country GI: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 20), (23), PASSIVE-SCAN + (5250 - 5330 @ 20), (23), PASSIVE-SCAN, DFS + (5490 - 5710 @ 20), (23), PASSIVE-SCAN, DFS + (5735 - 5835 @ 20), (14), PASSIVE-SCAN + +country EU: DFS-ETSI + # AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,GB,IS,LI,NO,CH,AL,ME,RS,MK,TR,BA + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (30), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (14), PASSIVE-SCAN country GL: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country GP: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country GR: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country GT: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country GU: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) - -country GY: - (2402 - 2482 @ 40), (30) - (5735 - 5835 @ 80), (30) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (30), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (14), PASSIVE-SCAN country HK: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: FCC/EU - (57240 - 65880 @ 2160), (40) - -country HN: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (24) - (5490 - 5730 @ 160), (24) - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) - -country HR: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country HT: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country HU: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (23), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN country ID: # ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf - (2402 - 2482 @ 40), (30) - (5735 - 5815 @ 20), (30) - -country IE: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5735 - 5815 @ 20), (30), PASSIVE-SCAN country IL: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - # 60 gHz band channels 1-4, base on Etsi En 302 567 - (57000 - 66000 @ 2160), (40) + (2402 - 2482 @ 20), (20) + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW -country IN: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (23) - (5735 - 5835 @ 80), (30) - -country IS: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) +country IN: DFS-ETSI + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5735 - 5835 @ 80), (23), PASSIVE-SCAN -country IT: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) +country IQ: DFS-ETSI + (2402 - 2482 @ 20), (19) + (5170 - 5250 @ 80), (21), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (21), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (21), PASSIVE-SCAN, DFS country JM: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) + (2402 - 2482 @ 20), (20) + (5735 - 5835 @ 80), (27) country JO: - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23) - (5735 - 5835 @ 80), (23) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) + (2402 - 2482 @ 20), (20) + (5735 - 5835 @ 80), (23), PASSIVE-SCAN country JP: DFS-JP - (2402 - 2482 @ 40), (20) - (2474 - 2494 @ 20), (20), NO-OFDM - (5170 - 5250 @ 80), (20), AUTO-BW, NO-OUTDOOR - (5250 - 5330 @ 80), (20), DFS, AUTO-BW, NO-OUTDOOR - (5490 - 5710 @ 160), (20), DFS - # 60 gHz band channels 1-4 - (57240 - 65880 @ 2160), (40) - -country KE: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23) - (5490 - 5570 @ 80), (30), DFS - (5735 - 5775 @ 40), (23) - -country KH: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country KN: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5735 - 5815 @ 80), (30) + (2402 - 2482 @ 20), (20) + (5170 - 5250 @ 80), (20), PASSIVE-SCAN, AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (20), PASSIVE-SCAN, DFS, AUTO-BW, NO-OUTDOOR + (5490 - 5710 @ 160), (20), PASSIVE-SCAN, DFS country KR: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5490 - 5730 @ 160), (30), DFS - (5735 - 5835 @ 80), (30) - # 60 GHz band channels 1-4, - # ref: http://www.law.go.kr/%ED%96%89%EC%A0%95%EA%B7%9C%EC%B9%99/%EB%AC%B4%EC%84%A0%EC%84%A4%EB%B9%84%EA%B7%9C%EC%B9%99 - (57240 - 65880 @ 2160), (43) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (17), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (20), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 80), (20), PASSIVE-SCAN, DFS + (5735 - 5815 @ 80), (20), PASSIVE-SCAN country KW: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - -country KY: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country KZ: - (2402 - 2482 @ 40), (20) - -country LB: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country LC: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (30), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5735 - 5815 @ 80), (30) - -country LI: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country LK: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 20), (24) - (5250 - 5330 @ 20), (24), DFS - (5490 - 5730 @ 20), (24), DFS - (5735 - 5835 @ 20), (30) - -country LS: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country LT: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country LU: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country LV: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) + (2402 - 2482 @ 20), (20) + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW country MA: DFS-ETSI - (2402 - 2482 @ 40), (20) + (2402 - 2482 @ 20), (20) (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW country MC: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country MD: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country ME: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country MF: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country MH: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country MK: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country MN: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country MO: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country MP: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country MQ: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country MR: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country MT: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country MU: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country MV: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5735 - 5835 @ 80), (20) - -country MW: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (30), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (14) country MX: DFS-FCC - (2402 - 2482 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) + (2402 - 2472 @ 20), (30) + # Channel 12 - 13. + (2457 - 2482 @ 20), (30), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (17), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5590 @ 80), (24), PASSIVE-SCAN, DFS + (5650 - 5710 @ 40), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN country MY: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5650 @ 160), (24), DFS - (5735 - 5815 @ 80), (24) - # 60 gHz band channels 1-3 - (57240 - 63720 @ 2160), (40) - -country NA: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5730 @ 160), (30), DFS - (5735 - 5835 @ 80), (33) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (24), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5650 @ 160), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (24), PASSIVE-SCAN country NG: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5250 - 5330 @ 80), (30), DFS - (5735 - 5835 @ 80), (30) - -country NI: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) - -country NL: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country NO: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country NP: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (20) - (5735 - 5835 @ 80), (20) + (2402 - 2482 @ 20), (20) + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (23), PASSIVE-SCAN country NZ: DFS-FCC - (2402 - 2482 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5590 @ 80), (23), PASSIVE-SCAN, DFS + (5650 - 5710 @ 40), (23), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (14), PASSIVE-SCAN country OM: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country PA: - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (23), AUT0-BW - (5250 - 5330 @ 80), (30), AUTO-BW - (5735 - 5835 @ 80), (36) + (2402 - 2482 @ 20), (20) + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (30), PASSIVE-SCAN, DFS country PE: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country PF: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country PG: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (24), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (21), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN country PH: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country PK: - (2402 - 2482 @ 40), (30) - (5735 - 5835 @ 80), (30) - -country PL: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country PM: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5730 @ 160), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN country PR: DFS-FCC - (2402 - 2472 @ 40), (30) + (2402 - 2472 @ 20), (30) (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -# Public Safety FCCA, FCC4 -# 27dBm [4.9GHz 1/4 rate], 30dBm [1/2 rate], 33dBm [full rate], and 5GHz same as FCC1 -# db.txt cannot express the limitation on 5G so disable all 5G channels for FCC4 -country PS: DFS-FCC - (2402 - 2472 @ 40), (30) - (4940 - 4990 @ 40), (33) - -country PT: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country PW: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5730 @ 160), (24), PASSIVE-SCAN, DFS (5735 - 5835 @ 80), (30) country PY: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS + (2402 - 2482 @ 20), (20) + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (24), PASSIVE-SCAN, DFS (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) country QA: - (2402 - 2482 @ 40), (20) - (5735 - 5835 @ 80), (30) - -country RE: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country RO: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -# Source: -# http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf -country RS: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country RU: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (23) - (5490 - 5730 @ 160), (30) - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 - (57240 - 65880 @ 2160), (40) + (2402 - 2482 @ 20), (10) + (5735 - 5835 @ 80), (14), PASSIVE-SCAN -country RW: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) +country RU: DFS-ETSI + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (20), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (20), PASSIVE-SCAN, DFS, AUTO-BW + (5650 - 5710 @ 40), (20), PASSIVE-SCAN, DFS country SA: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country SE: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (30), PASSIVE-SCAN, DFS + (5735 - 5815 @ 80), (14) country SG: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40), NO-OUTDOOR - -country SI: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country SK: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - -country SN: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (24) - (5490 - 5730 @ 160), (24) - (5735 - 5835 @ 80), (30) - -country SR: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country SV: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 20), (23) - (5250 - 5330 @ 20), (23), DFS - (5735 - 5835 @ 20), (30) - -country TC: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country TD: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country TG: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 40), (23) - (5250 - 5330 @ 40), (23), DFS - (5490 - 5710 @ 40), (30), DFS + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (24), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN country TH: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 - (57240 - 65880 @ 2160), (40) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN country TN: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - -country TR: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country TT: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (27) - (5490 - 5730 @ 160), (36) - (5735 - 5835 @ 80), (36) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) + (2402 - 2482 @ 20), (20), PASSIVE-SCAN + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW country TW: DFS-FCC - (2402 - 2472 @ 40), (30) + (2402 - 2472 @ 20), (30) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-3, FCC - (57240 - 63720 @ 2160), (40) - -country TZ: - (2402 - 2482 @ 40), (20) - (5735 - 5835 @ 80), (30) + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5710 @ 160), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN # Source: # #914 / 06 Sep 2007: http://www.ucrf.gov.ua/uk/doc/nkrz/1196068874 @@ -1402,131 +342,54 @@ country TZ: # rules in the referenced laws. Such a range is used because of # disputable definitions there. country UA: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5490 - 5670 @ 160), (20), DFS - (5735 - 5835 @ 80), (20) - # 60 gHz band channels 1-4, ref: Etsi En 302 567 - (57240 - 65880 @ 2160), (20) - -country UG: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (20), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (20), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5670 @ 160), (20), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (20), PASSIVE-SCAN country US: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (30), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS + (2402 - 2472 @ 20), (30) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (24), AUTO-BW + (5250 - 5330 @ 80), (24), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5730 @ 160), (24), PASSIVE-SCAN, DFS (5735 - 5835 @ 80), (30) - # 5.9ghz band - # reference: https://apps.fcc.gov/edocs_public/attachmatch/FCC-03-324A1.pdf - (5842 - 5863 @ 5), (30) - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5865 - 5885 @ 20), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5895 - 5915 @ 20), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) - # 60g band - # reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255 - # channels 1,2,3,4,5,6 EIRP=40dBm(43dBm peak) - (57240 - 70200 @ 2160), (40) country UY: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 - (57240 - 65880 @ 2160), (40) - -country UZ: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - -country VC: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS + (2402 - 2482 @ 20), (20), PASSIVE-SCAN + (5735 - 5835 @ 80), (30), PASSIVE-SCAN country VE: DFS-FCC - (2402 - 2482 @ 40), (30) + (2402 - 2482 @ 20), (30) (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5735 - 5835 @ 80), (30) - -country VI: DFS-FCC - (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW (5735 - 5835 @ 80), (30) -country VN: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 - (57240 - 65880 @ 2160), (40) - -country VU: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -country WF: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - -country WS: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 40), (23) - (5250 - 5330 @ 40), (23), DFS - (5490 - 5710 @ 40), (30), DFS - -country XA: DFS-JP - (2402 - 2482 @ 40), (20) - (2474 - 2494 @ 20), (20), NO-OFDM - (5170 - 5250 @ 80), (20), NO-IR, AUTO-BW, NO-OUTDOOR - (5250 - 5330 @ 80), (20), DFS, AUTO-BW, NO-OUTDOOR - (5490 - 5710 @ 160), (20), DFS - -country YE: - (2402 - 2482 @ 40), (20) +country XA + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS -country YT: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS +country XC + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + # Channel 36 - 48 + (5170 - 5250 @ 80), (20), PASSIVE-SCAN, NO-IBSS + # Channel 52 - 64 + (5250 - 5330 @ 80), (20), PASSIVE-SCAN, NO-IBSS + # Channel 132 - 140 + (5650 - 5710 @ 40), (20), PASSIVE-SCAN, NO-IBSS country ZA: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - # 60 gHz band channels 1-4 - (57240 - 65880 @ 2160), (40), NO-OUTDOOR - -country ZW: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS + (2402 - 2472 @ 20), (20) + # Channel 12 - 13. + (2457 - 2482 @ 20), (20), PASSIVE-SCAN, NO-IBSS + (5170 - 5250 @ 80), (23), PASSIVE-SCAN, AUTO-BW + (5250 - 5330 @ 80), (23), PASSIVE-SCAN, DFS, AUTO-BW + (5490 - 5730 @ 160), (24), PASSIVE-SCAN, DFS + (5735 - 5835 @ 80), (30), PASSIVE-SCAN diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2a9ec3e05c73aca0dd1ed6f645026b2c4cff43b4..d0d09c290ff8fc444363fd2e6bfbfc27a43339a8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -302,7 +302,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, [NL80211_ATTR_PID] = { .type = NLA_U32 }, [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, - [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN }, + [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, + .len = WLAN_PMKID_LEN }, [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, @@ -358,7 +359,6 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, - [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = {. type = NLA_U32 }, [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, @@ -6124,10 +6124,6 @@ static int validate_scan_freqs(struct nlattr *freqs) struct nlattr *attr1, *attr2; int n_channels = 0, tmp1, tmp2; - nla_for_each_nested(attr1, freqs, tmp1) - if (nla_len(attr1) != sizeof(u32)) - return 0; - nla_for_each_nested(attr1, freqs, tmp1) { n_channels++; /* diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index bda1a13628a8143b812554d0d29fd83cac3a1e36..0a9b7e87936f460927b19380ca9b4d9b26bcbfa5 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig @@ -83,3 +83,12 @@ config NET_KEY_MIGRATE If unsure, say N. +config XFRM_RFC_4868_TRUNCATION + bool "Use truncation length of RFC4868 for HMAC-SHA-256" + depends on XFRM + default n + ---help--- + Tentatively, truncate length of HMAC-SHA-256 is 96bit. + RFC4868 fixed it to 128bit. + + If unsure, say N. diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 9adfdd711b31766c1611bbac90e75f7f9c0b90d2..2e232f7e29ed8f18f36b9eb885a6a2bd73c85f69 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -8,6 +8,11 @@ * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -239,7 +244,11 @@ static struct xfrm_algo_desc aalg_list[] = { .uinfo = { .auth = { +#ifdef CONFIG_XFRM_RFC_4868_TRUNCATION .icv_truncbits = 128, +#else + .icv_truncbits = 96, +#endif .icv_fullbits = 256, } }, diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 0f45e1a3a7d146ec3d0ecabd7a40f6331139d4ed..d5b4ac7bf0d817bf242373c6a62b4d0d9ec1ae2d 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1773,6 +1773,43 @@ free_dst: goto out; } +#ifdef CONFIG_XFRM_SUB_POLICY +static int xfrm_dst_alloc_copy(void **target, const void *src, int size) +{ + if (!*target) { + *target = kmalloc(size, GFP_ATOMIC); + if (!*target) + return -ENOMEM; + } + + memcpy(*target, src, size); + return 0; +} +#endif + +static int xfrm_dst_update_parent(struct dst_entry *dst, + const struct xfrm_selector *sel) +{ +#ifdef CONFIG_XFRM_SUB_POLICY + struct xfrm_dst *xdst = (struct xfrm_dst *)dst; + return xfrm_dst_alloc_copy((void **)&(xdst->partner), + sel, sizeof(*sel)); +#else + return 0; +#endif +} + +static int xfrm_dst_update_origin(struct dst_entry *dst, + const struct flowi *fl) +{ +#ifdef CONFIG_XFRM_SUB_POLICY + struct xfrm_dst *xdst = (struct xfrm_dst *)dst; + return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl)); +#else + return 0; +#endif +} + static int xfrm_expand_policies(const struct flowi *fl, u16 family, struct xfrm_policy **pols, int *num_pols, int *num_xfrms) @@ -1844,6 +1881,16 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, xdst = (struct xfrm_dst *)dst; xdst->num_xfrms = err; + if (num_pols > 1) + err = xfrm_dst_update_parent(dst, &pols[1]->selector); + else + err = xfrm_dst_update_origin(dst, fl); + if (unlikely(err)) { + dst_free(dst); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); + return ERR_PTR(err); + } + xdst->num_pols = num_pols; memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols); xdst->policy_genid = atomic_read(&pols[0]->genid); diff --git a/scripts/autoconfig.pl b/scripts/autoconfig.pl new file mode 100755 index 0000000000000000000000000000000000000000..df8fba46eea5f0c945c36f10b471f55d3ebccfaf --- /dev/null +++ b/scripts/autoconfig.pl @@ -0,0 +1,288 @@ +#!/usr/bin/perl + +# scripts/defconfig.pl +# +# Copyright (C) 2011 Sony Ericsson Mobile Communications AB. +# +# Author: Martin Danielsson +# +# 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; either version 2 +# of the License, or (at your option) any later version. + +use strict; +use warnings; + +use Cwd 'abs_path'; +use File::Copy; + +my $defconfig; +my $kernel_dir; +my $config_dir; +my @products = (); +my $keep_tempconfig; + +# Print usage instructions +# +# In: Error message to display +sub usage($) +{ + my ($msg) = @_; + + print "\n"; + print "Error: $msg\n\n" if ($msg ne ""); + + print "This script is used to perform one or more tasks on a set of\n"; + print "defconfig files. The result will be the same as if the\n"; + print "product configuration was done using menuconfig or similar\n"; + print "tool.\n\n"; + + print "Usage: "; + print "autoconfig.pl [-k] -t [:[=]] \n\n"; + + print "-k: keep .config file after execution\n"; + print "\t.config file is removed as default behavior\n"; + print "\tbecause remaining .config file causes build error\n"; + print "\tuse this flag to stop removing (for debug purpose)\n"; + print "-t: task for new configuration\n"; + print " - action to perform\n"; + print "\ts: sync defconfig with Kconfig (s)\n"; + print "\ta: set a configuration (a:=)\n"; + print "\td: unset a configuration (d:)\n"; + print " - a configuration flag, for instance CONFIG_SWAP\n"; + print " - the value to set, for instance y, n or 1000\n"; + print "Examples:\n"; + print "\tSync all defconfigs with Kconfig\n"; + print "\t\$ autoconfig.pl -t s\n\n"; + print "\tEnable CONFIG_SWAP for Anzu and Hallon\n"; + print "\t\$ autoconfig.pl -t a:CONFIG_SWAP=y anzu hallon\n\n"; + print "\tDisable CONFIG_USB_SUPPORT for all products\n"; + print "\t\$ autoconfig.pl -t d:CONFIG_USB_SUPPORT\n\n"; + print "\tSet CONFIG_MSM_AMSS_VERSION to 1000 for Anzu\n"; + print "\t\$ autoconfig.pl -t a:CONFIG_MSM_AMSS_VERSION=1000 anzu\n"; + print "\n"; +} + +# Apply a modification to a defconfig file +# +# In: The key +# In: The value +sub apply_modification($$) +{ + my ($key, $value) = @_; + + # Settings are applied by inserting them at the end of the defconfig + # file. The kernel build system will later move it to the correct + # location and handle any duplicate entries. It will also perform + # validation of integer values. + my $file = ".config"; + open DEFCONFIG, ">>$file" or die "Failed to open file, $file"; + if ($value eq "n") { + print DEFCONFIG "\n# $key is not set\n"; + } else { + print DEFCONFIG "\n$key=$value\n"; + } + close DEFCONFIG; +} + +sub perform_task_diffconfig($$$) +{ + my ($action, $key, $value) = @_; + opendir Dir, "$config_dir/diffconfig" or exit 0; + foreach (readdir Dir) { + if (/([\w-]+)_diffconfig/) { + if ($action eq "s") { + print "Syncing $_ ...\n"; + } + if (@products != 0) { + if (is_product_selected($1) == 0) { + next; + } + if ($action eq "a") { + print "Setting $key=$value in $_...\n"; + } elsif ($action eq "d") { + print "Removing $key in $_...\n"; + } + } + if ((is_product_excluded($1) == 0)) { + $ENV{'KBUILD_DIFFCONFIG'} = $_; + system "make ARCH=arm64 `basename $defconfig` > /dev/null 2>&1"; + if ($action ne "s") { + apply_modification($key, $value); + system "make ARCH=arm64 `basename olddefconfig` > /dev/null 2>&1"; + } + $ENV{'KBUILD_DIFFCONFIG'} = $_; + system "make ARCH=arm64 savediffconfig > /dev/null 2>&1"; + move("diffconfig", "$config_dir/diffconfig/$_") + or die "failed to copy file"; + } + } + } + close Dir; +} + + +# Perform a task on a specific defconfig +# +# In: The action +# In: The key +# In: The value +sub perform_task_defconfig($$$) +{ + my ($action, $key, $value) = @_; + + if ($action eq "s") { + print "Syncing $defconfig ...\n"; + } elsif ($action eq "a") { + print "Setting $key=$value ...\n"; + } elsif ($action eq "d") { + print "Removing $key ...\n"; + } + + if (@products == 0) { + #Updating the common diffconfig + my $option ="KCONFIG_NOTIMESTAMP=true"; + $ENV{'KBUILD_DIFFCONFIG'} = "common_diffconfig"; + system "make ARCH=arm64 `basename $defconfig` > /dev/null 2>&1"; + if ($action ne "s") { + apply_modification($key, $value); + system "make ARCH=arm64 olddefconfig > /dev/null 2>&1"; + } + system "make ARCH=arm64 savecommondiffconfig > /dev/null 2>&1"; + move("diffconfig.common", "$config_dir/diffconfig/common_diffconfig") + or die "failed to copy file"; + } + + perform_task_diffconfig($action, $key, $value); +} + + + +# Parse a task description string +# +# In: The task description string +# Out: A ($action, $key, $value) array. In case of error $action is set to "-" +sub parse_task_description($) +{ + my ($task) = @_; + + my $action = ""; + my $key = ""; + my $value = ""; + if ($task =~ /^([sda])/) { + $action = $1; + } else { + print "unknown action, $task\n"; + return ("-", "", ""); + } + my $error = 1; + if ($action eq "s") { + $error = 0; + } elsif ($action eq "a") { + if ($task =~ /^a:(\w+)=(.+)/) { + $key = $1; + $value = $2; + $error = 0; + } + } elsif ($action eq "d") { + if ($task =~ /^d:(\w+)/) { + $key = $1; + $value = "n"; + $error = 0; + } + } + if ($error == 1) { + print "incorrect task description, $task\n"; + return ("-", "", ""); + } + + return ($action, $key, $value); +} + +# Check if a product should be excluded +# +# In: The product to check +# Out: 1 if the product is excluded, 0 otherwise +sub is_product_excluded($) +{ + my ($product) = @_; + + if ($product =~ /_capk/) { + return 1; + } + + if ($product =~ /common/) { + return 1; + } + + return 0; +} + +# Check if a product has been selected for processing +# +# In: The product to check +# Out: 1 if the product selected, 0 otherwise +sub is_product_selected($) +{ + my ($product) = @_; + + if (@products == 0) { + return 1; + } + foreach (@products) { + if ($product eq $_) { + return 1; + } + } + + return 0; +} + +### Program starts here ### + +# Figure out the path to the kernel directory and move to it +$defconfig = "msmcortex-perf_defconfig"; +$kernel_dir = abs_path($0); +$kernel_dir =~ s!/scripts/.*\.pl!!; +chdir $kernel_dir or die "couldn't move to kernel directory, $kernel_dir\n"; +$config_dir = "$kernel_dir/arch/arm64/configs"; +$keep_tempconfig = 0; + +# Parse command line arguments +my @tasks = (); +my $iter = 0; +my $flag = 0; +while ($iter < @ARGV) { + if ($ARGV[$iter] eq "-t") { + $iter++; + if ($iter >= @ARGV) { + usage("not enough arguments"); + exit 0; + } + push @tasks, $ARGV[$iter]; + } elsif ($ARGV[$iter] eq "-h") { + usage(""); + exit 0; + } elsif ($ARGV[$iter] eq "-k") { + $keep_tempconfig = 1; + } else { + push @products, $ARGV[$iter]; + } + $iter++; +} + +# Apply the tasks one at a time for each selected product +if (@tasks == 0) { + usage("no task specified"); + exit 0; +} +my $task; +foreach $task (@tasks) { + my ($action, $key, $value) = parse_task_description($task); + next if ($action eq "-"); + perform_task_defconfig($action, $key, $value); + if ($keep_tempconfig == 0) { + system "make mrproper"; + } +} diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 31898856682e50a3b3dfd32b9d8ef17ab59e2e3d..696ccfa08d103cd29ae56ac38c117bbd7725da06 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -428,7 +428,7 @@ static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key, static struct key *request_master_key(struct encrypted_key_payload *epayload, const u8 **master_key, size_t *master_keylen) { - struct key *mkey = ERR_PTR(-EINVAL); + struct key *mkey = NULL; if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) { diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index b428e1b8b11ccbd65a41ebea57610cd962e8908c..3a12dd172d04c45b321245137c3ccebd2d1fea6f 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -527,12 +527,10 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, kc_update_timestamp(entry); entry->state = ACTIVE_ICE_LOADED; - if (!strcmp(s_type, (char *)PFK_UFS)) { - if (async) - entry->loaded_ref_cnt++; - } else { + if (async && (!strcmp(s_type, + (char *)PFK_UFS))) entry->loaded_ref_cnt++; - } + break; } case (FREE): @@ -546,16 +544,14 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, entry->state = ACTIVE_ICE_LOADED; /* - * In case of UFS only increase ref cnt for async calls, + * only increase ref cnt for async calls, * sync calls from within work thread do not pass * requests further to HW */ - if (!strcmp(s_type, (char *)PFK_UFS)) { - if (async) - entry->loaded_ref_cnt++; - } else { + if (async && (!strcmp(s_type, + (char *)PFK_UFS))) entry->loaded_ref_cnt++; - } + } break; case (ACTIVE_ICE_PRELOAD): @@ -565,12 +561,9 @@ int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, case (ACTIVE_ICE_LOADED): kc_update_timestamp(entry); - if (!strcmp(s_type, (char *)PFK_UFS)) { - if (async) - entry->loaded_ref_cnt++; - } else { + if (async && (!strcmp(s_type, + (char *)PFK_UFS))) entry->loaded_ref_cnt++; - } break; case(SCM_ERROR): ret = entry->scm_error; @@ -628,24 +621,36 @@ void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, return; } - ref_cnt = --entry->loaded_ref_cnt; + if (!strcmp(s_type, (char *)PFK_UFS)) { + ref_cnt = --entry->loaded_ref_cnt; - if (ref_cnt < 0) - pr_err("internal error, ref count should never be negative\n"); + if (ref_cnt < 0) + pr_err("internal error, ref count should never be negative\n"); - if (!ref_cnt) { + if (!ref_cnt) { + entry->state = INACTIVE; + /* + * wake-up invalidation if it's waiting + * for the entry to be released + */ + if (entry->thread_pending) { + tmp_pending = entry->thread_pending; + entry->thread_pending = NULL; + + kc_spin_unlock(); + wake_up_process(tmp_pending); + return; + } + } + } else { entry->state = INACTIVE; /* - * wake-up invalidation if it's waiting - * for the entry to be released - */ + * wake-up invalidation if it's waiting + * for the entry to be released + */ if (entry->thread_pending) { - tmp_pending = entry->thread_pending; + wake_up_process(entry->thread_pending); entry->thread_pending = NULL; - - kc_spin_unlock(); - wake_up_process(tmp_pending); - return; } } diff --git a/security/security.c b/security/security.c index b636dd5caa77bf8b910646c427daed7b4aa9c5f3..e4022dd0d497d4da330160807957cfca2e2356d9 100644 --- a/security/security.c +++ b/security/security.c @@ -10,6 +10,11 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 8691e92f27e584dcf26f35628c61e408c08a77cb..6e31e646366ec9a1cc8d6586a86e97e20eb7a2f4 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -74,6 +74,16 @@ config SECURITY_SELINUX_AVC_STATS /selinux/avc/cache_stats, which may be monitored via tools such as avcstat. +config SECURITY_SELINUX_AVC_EXTRA_INFO + bool "SELinux extended log info" + depends on SECURITY_SELINUX + default n + help + This option enables extra log info providing information + about the audit result and the process under audit, such + as thread group and parent pid. Appended log tags are: + "ppid", "pcomm", "pgid", pgcomm" and "op_res". + config SECURITY_SELINUX_CHECKREQPROT_VALUE int "NSA SELinux checkreqprot default value" depends on SECURITY_SELINUX @@ -131,3 +141,12 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE installed under /etc/selinux/$SELINUXTYPE/policy, where SELINUXTYPE is defined in your /etc/selinux/config. + +config SECURITY_SELINUX_TRAP + bool "SELinux error trap support" + depends on SECURITY_SELINUX + default n + help + This option enables the trap feature for SELinux errors. + User process will get SIGABRT so that system can generate core file + for more further invesitaion of SELinux errors. diff --git a/security/selinux/Makefile b/security/selinux/Makefile index ad5cd76ec231cd14f02b2fb15f07a3d8a069972f..212bb4b8d781e76565abd2e248f8e3916ab7b967 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -9,6 +9,8 @@ selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o +selinux-$(CONFIG_SECURITY_SELINUX_TRAP) += trap.o + selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o selinux-$(CONFIG_NETLABEL) += netlabel.o diff --git a/security/selinux/avc.c b/security/selinux/avc.c index e60c79de13e1c74ea6129cfb5431d5d2415cdc2d..b979de146c82507941560a7fba6fec1fd34542d5 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -13,6 +13,11 @@ * it under the terms of the GNU General Public License version 2, * as published by the Free Software Foundation. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -33,6 +38,10 @@ #include "avc.h" #include "avc_ss.h" #include "classmap.h" +#ifdef CONFIG_SECURITY_SELINUX_TRAP +#include "trap.h" +const int secclass_map_size = ARRAY_SIZE(secclass_map); +#endif #define AVC_CACHE_SLOTS 512 #define AVC_DEF_CACHE_THRESHOLD 512 @@ -718,6 +727,35 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) audit_log_format(ab, " for "); } +/** + * avc_dump_extra_info - add extra info about task and audit result + * @ab: the audit buffer + * @ad: audit_data + */ +#ifdef CONFIG_SECURITY_SELINUX_AVC_EXTRA_INFO +static void avc_dump_extra_info(struct audit_buffer *ab, + struct common_audit_data *ad) +{ + struct task_struct *tsk = current; + + if (tsk && tsk->pid) { + audit_log_format(ab, " ppid=%d pcomm=", tsk->parent->pid); + audit_log_untrustedstring(ab, tsk->parent->comm); + + if (tsk->group_leader->pid != tsk->pid) { + audit_log_format(ab, " pgid=%d pgcomm=", + tsk->group_leader->pid); + audit_log_untrustedstring(ab, + tsk->group_leader->comm); + } else if (tsk->parent->group_leader->pid) { + audit_log_format(ab, " pgid=%d pgcomm=", + tsk->parent->group_leader->pid); + audit_log_untrustedstring(ab, + tsk->parent->group_leader->comm); + } + } +} +#endif /** * avc_audit_post_callback - SELinux specific information * will be called by generic audit code @@ -735,6 +773,14 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) audit_log_format(ab, " permissive=%u", ad->selinux_audit_data->result ? 0 : 1); } + +#ifdef CONFIG_SECURITY_SELINUX_AVC_EXTRA_INFO + avc_dump_extra_info(ab, ad); +#endif +#ifdef CONFIG_SECURITY_SELINUX_TRAP + if (ad->selinux_audit_data->denied && ad->selinux_audit_data->result) + trap_selinux_error(ad); +#endif } /* This is the slow part of avc audit with big stack footprint */ diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d0221769ba5268b742eb768235c2a3c0480e5277..5ab9d1e3e2b870f7623fd533b4ef7b59f129a52f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -740,7 +740,6 @@ static int selinux_set_mnt_opts(struct super_block *sb, sbsec->flags |= SE_SBPROC | SE_SBGENFS; if (!strcmp(sb->s_type->name, "debugfs") || - !strcmp(sb->s_type->name, "tracefs") || !strcmp(sb->s_type->name, "sysfs") || !strcmp(sb->s_type->name, "pstore")) sbsec->flags |= SE_SBGENFS; diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index d5c328452df0161acd82bd8ec295fecc00392b86..834f8f8f0faac81fa84a2421c940d23cc31ce647 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h @@ -3,6 +3,11 @@ * * Author : Stephen Smalley, */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _SELINUX_AVC_SS_H_ #define _SELINUX_AVC_SS_H_ @@ -17,7 +22,9 @@ struct security_class_mapping { }; extern struct security_class_mapping secclass_map[]; - +#ifdef CONFIG_SECURITY_SELINUX_TRAP +extern const int secclass_map_size; +#endif /* * The security server must be initialized before * any labeling or access decisions can be provided. diff --git a/security/selinux/include/trap.h b/security/selinux/include/trap.h new file mode 100644 index 0000000000000000000000000000000000000000..9732c29563d3d280fe20471b2de8ac9ea77e9ca1 --- /dev/null +++ b/security/selinux/include/trap.h @@ -0,0 +1,74 @@ +/* + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef _SELINUX_TRAP_H_ +#define _SELINUX_TRAP_H_ + +#include +#include +#include +#include +#include "avc.h" + +enum trap_mask_type { + TRAP_MASK_TYPE_POLARITY, + TRAP_MASK_TYPE_SCONTEXT, + TRAP_MASK_TYPE_TCONTEXT, + TRAP_MASK_TYPE_TCLASS, + TRAP_MASK_TYPE_PNAME, + TRAP_MASK_TYPE_PNAME_PARENT, + TRAP_MASK_TYPE_PNAME_PGL, + TRAP_MASK_TYPE_PATH, + TRAP_MASK_TYPE_NAME, + TRAP_MASK_TYPE_ACTION, + TRAP_MASK_TYPE_MAX +}; +enum trap_loglevel_type { + TRAP_LOGLEVEL_MINIMUM = 0, + TRAP_LOGLEVEL_NORMAL, + TRAP_LOGLEVEL_DEVELOPER, + TRAP_LOGLEVEL_MAX +}; + +#define TRAP_MASK_TYPE_BEGIN TRAP_MASK_TYPE_POLARITY + +struct selinux_trap_list { + char *item_array[TRAP_MASK_TYPE_MAX]; + struct list_head list; + struct rcu_head rcu; +}; + +struct selinux_trap_process_list { + struct list_head list; + pid_t pid; + char *msg; + struct inode *inode; + struct dentry *ldentry; +}; + +void trap_selinux_error(struct common_audit_data *ad); +extern int selinux_trap_enable; +extern int selinux_trap_debug; +extern struct selinux_trap_list selinux_trap_list_head; +extern struct selinux_trap_process_list selinux_trap_process_list_head; +extern struct semaphore selinux_trap_list_sem; + +#define trap_devel_log(fmt, ...) \ + do { /* Multhi-statement Macro for semicolon */ \ + if (selinux_trap_debug >= TRAP_LOGLEVEL_DEVELOPER) { \ + pr_devel(fmt, ##__VA_ARGS__); \ + } \ + } while (0) /* Multhi-statement Macro for semicolon */ + +#endif /* _SELINUX_TRAP_H_ */ diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index c02da25d7b631992aa7841ca98250b08b48d8477..55460e8d1e7875281c8e15be4fcfed5746aea400 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -13,6 +13,11 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -40,6 +45,9 @@ #include "security.h" #include "objsec.h" #include "conditional.h" +#ifdef CONFIG_SECURITY_SELINUX_TRAP +#include "trap.h" +#endif /* Policy capability filenames */ static char *policycap_names[] = { @@ -1429,6 +1437,476 @@ static const struct file_operations sel_avc_cache_stats_ops = { }; #endif +#ifdef CONFIG_SECURITY_SELINUX_TRAP +static void sel_trap_clear_list_entry(struct selinux_trap_list *entry) +{ + enum trap_mask_type type; + for (type = TRAP_MASK_TYPE_BEGIN; type != TRAP_MASK_TYPE_MAX; type++) + kfree(entry->item_array[type]); + kfree(entry); +} + +static void sel_trap_clear_list_entry_rcu(struct rcu_head *rcu) +{ + struct selinux_trap_list *entry = + container_of(rcu, struct selinux_trap_list, rcu); + sel_trap_clear_list_entry(entry); +} + +static struct selinux_trap_list *sel_trap_init_list_entry(char *buf) +{ + struct selinux_trap_list *entry; + enum trap_mask_type type = TRAP_MASK_TYPE_BEGIN; + char *token; + int buflen = strlen(buf); + int valid_count = 0; + + if (buflen <= 0) + return NULL; + + if (buf[buflen-1] == '\n') + buf[buflen-1] = '\0'; + + entry = kzalloc(sizeof(struct selinux_trap_list), GFP_KERNEL); + if (!entry) { + printk(KERN_ERR "SELinux: trap: kmalloc() failed\n"); + return NULL; + } + + while ((token = strsep(&buf, ",")) != NULL) { + if (type == TRAP_MASK_TYPE_MAX) { + sel_trap_clear_list_entry(entry); + return NULL; + } + if (strlen(token) > 0) { + entry->item_array[type] = + kzalloc(strlen(token)+1, GFP_KERNEL); + if (!entry->item_array[type]) { + sel_trap_clear_list_entry(entry); + return NULL; + } + strlcpy(entry->item_array[type], + token, strlen(token)+1); + valid_count++; + } + type++; + } + if (valid_count == 0 || type != TRAP_MASK_TYPE_MAX) { + sel_trap_clear_list_entry(entry); + return NULL; + } + return entry; +} + +static ssize_t sel_read_trap_enable(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + char tmpbuf[2]; + ssize_t length; + + length = scnprintf(tmpbuf, sizeof(tmpbuf), "%d", selinux_trap_enable); + return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); +} + +static ssize_t sel_write_trap_enable(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + +{ + char *page = NULL; + ssize_t length; + int new_value; + + length = -ENOMEM; + if (count >= PAGE_SIZE) + goto out; + + /* No partial writes. */ + length = EINVAL; + if (*ppos != 0) + goto out; + + length = -ENOMEM; + page = (char *)get_zeroed_page(GFP_KERNEL); + if (!page) + goto out; + + length = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + length = -EINVAL; + if (sscanf(page, "%d", &new_value) != 1) + goto out; + + if (new_value == 0 || new_value == 1) + selinux_trap_enable = new_value; + + length = count; +out: + free_page((unsigned long) page); + return length; +} + +static const struct file_operations sel_trap_enable_ops = { + .read = sel_read_trap_enable, + .write = sel_write_trap_enable, + .llseek = generic_file_llseek, +}; + +static int show_trap_exceptions(struct seq_file *m, void *v) +{ + struct selinux_trap_list *entry; + enum trap_mask_type type; + + seq_printf(m, + "{-|+},scontext,tcontext,tclass," + "pname,pname_parent,pname_pgl," + "path,name,types\n"); + + rcu_read_lock(); + list_for_each_entry_rcu(entry, &selinux_trap_list_head.list, list) { + for (type = TRAP_MASK_TYPE_BEGIN; + type < TRAP_MASK_TYPE_MAX; type++) { + if (entry->item_array[type]) + seq_printf(m, "%s", entry->item_array[type]); + if (type != TRAP_MASK_TYPE_MAX-1) + seq_printf(m, ","); + } + seq_printf(m, "\n"); + } + rcu_read_unlock(); + return 0; +} + +static int sel_open_trap_exceptions(struct inode *inode, struct file *file) +{ + return single_open(file, show_trap_exceptions, NULL); +} + +static const struct file_operations sel_trap_exceptions_ops = { + .open = sel_open_trap_exceptions, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static ssize_t sel_write_trap_add_exception(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + char *page = NULL; + ssize_t length; + struct selinux_trap_list *new_entry; + + length = -ENOMEM; + if (count >= PAGE_SIZE) + goto out; + + /* No partial writes. */ + length = EINVAL; + if (*ppos != 0) + goto out; + + /* string size error */ + length = EINVAL ; + if (count < 2) + goto out ; + + length = -ENOMEM; + page = (char *)get_zeroed_page(GFP_KERNEL); + if (!page) + goto out; + + length = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + new_entry = sel_trap_init_list_entry(page); + if (!new_entry) { + printk(KERN_ERR "SELinux: trap: sel_trap_init_list_entry failed\n"); + goto out; + } + down(&selinux_trap_list_sem); + list_add_rcu(&new_entry->list, &selinux_trap_list_head.list); + up(&selinux_trap_list_sem); + + length = count; +out: + free_page((unsigned long) page); + return length; +} + +static const struct file_operations sel_trap_add_exception_ops = { + .write = sel_write_trap_add_exception, + .llseek = generic_file_llseek, +}; + +static ssize_t sel_write_trap_clear_exceptions( + struct file *file, const char __user *buf, size_t count, loff_t *ppos) + +{ + char *page = NULL; + ssize_t length; + int value; + + length = -ENOMEM; + if (count >= PAGE_SIZE) + goto out; + + /* No partial writes. */ + length = EINVAL; + if (*ppos != 0) + goto out; + + length = -ENOMEM; + page = (char *)get_zeroed_page(GFP_KERNEL); + if (!page) + goto out; + + length = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + length = -EINVAL; + if (sscanf(page, "%d", &value) != 1) + goto out; + + if (value == 1) { + struct selinux_trap_list *entry, *n; + down(&selinux_trap_list_sem); + list_for_each_entry_safe(entry, + n, &selinux_trap_list_head.list, list) { + list_del_rcu(&entry->list); + call_rcu(&entry->rcu, sel_trap_clear_list_entry_rcu); + } + up(&selinux_trap_list_sem); + } + length = count; +out: + free_page((unsigned long) page); + return length; +} + +static const struct file_operations sel_trap_clear_exceptions_ops = { + .write = sel_write_trap_clear_exceptions, + .llseek = generic_file_llseek, +}; + +static ssize_t sel_read_trap_debug(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + char tmpbuf[2]; + ssize_t length; + + length = scnprintf(tmpbuf, sizeof(tmpbuf), "%d", selinux_trap_debug); + return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); +} + +static ssize_t sel_write_trap_debug(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) + +{ + char *page = NULL; + ssize_t length; + int new_value; + + length = -ENOMEM; + if (count >= PAGE_SIZE) + goto out; + + /* No partial writes. */ + length = EINVAL; + if (*ppos != 0) + goto out; + + length = -ENOMEM; + page = (char *)get_zeroed_page(GFP_KERNEL); + if (!page) + goto out; + + length = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + length = -EINVAL; + if (sscanf(page, "%d", &new_value) != 1) + goto out; + + if (new_value >= TRAP_LOGLEVEL_MINIMUM && new_value < TRAP_LOGLEVEL_MAX) + selinux_trap_debug = new_value; + + length = count; +out: + free_page((unsigned long) page); + return length; +} + +static const struct file_operations sel_trap_debug_ops = { + .read = sel_read_trap_debug, + .write = sel_write_trap_debug, + .llseek = generic_file_llseek, +}; + +static struct dentry *trapped_dentry; + +static int sel_make_trap_files(struct dentry *dir) +{ + int i; + static struct tree_descr files[] = { + { "enable", + &sel_trap_enable_ops, S_IRUGO|S_IWUSR }, + { "exceptions", + &sel_trap_exceptions_ops, S_IRUGO }, + { "add_exception", + &sel_trap_add_exception_ops, S_IWUSR }, + { "clear_exceptions", + &sel_trap_clear_exceptions_ops, S_IWUSR }, + { "debug", + &sel_trap_debug_ops, S_IRUGO|S_IWUSR }, + }; + + for (i = 0; i < ARRAY_SIZE(files); i++) { + struct inode *inode; + struct dentry *dentry; + + dentry = d_alloc_name(dir, files[i].name); + if (!dentry) + return -ENOMEM; + + inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); + if (!inode) + return -ENOMEM; + + inode->i_fop = files[i].ops; + inode->i_ino = ++sel_last_ino; + d_add(dentry, inode); + } + + /* Create a new node named 'trapped' */ + trapped_dentry = sel_make_dir(dir, "trapped", &sel_last_ino); + if (IS_ERR(trapped_dentry)) { + return -ENOMEM; + } + + return 0; +} + +static struct selinux_trap_process_list *sel_trap_process_list_entry(pid_t pid, char *msg, struct inode *inode, struct dentry *ldentry) +{ + struct selinux_trap_process_list *entry; + + entry = kmalloc(sizeof(struct selinux_trap_process_list), GFP_KERNEL); + if (!entry) { + printk(KERN_ERR "SELinux: trap: node list kmalloc() failed\n"); + kfree(msg); + return NULL; + } + + entry->pid = pid; + entry->msg = msg; + entry->inode = inode; + entry->ldentry = ldentry; + + down(&selinux_trap_list_sem); + list_add_tail(&entry->list, &selinux_trap_process_list_head.list); + up(&selinux_trap_list_sem); + + return entry; +} + +static int sel_trap_process_list_entry_clear(struct selinux_trap_process_list *entry) +{ + if (entry->msg) + kfree(entry->msg); + list_del(&entry->list); + kfree(entry); + return 0; +} + +static int show_trap_trapped(struct seq_file *m, void *v) +{ + struct inode *inode = (struct inode *)m->private; + pid_t pid = inode->i_ino; + + rcu_read_lock(); + if (!list_empty(&selinux_trap_process_list_head.list)) { + struct selinux_trap_process_list *entry, *n; + down(&selinux_trap_list_sem); + list_for_each_entry_safe(entry, n, &selinux_trap_process_list_head.list, list) { + if (entry->pid == pid) { + seq_printf(m, "%s\n", entry->msg); + break; + } + } + up(&selinux_trap_list_sem); + } + rcu_read_unlock(); + return 0; +} + +static int sel_open_trap_trapped(struct inode *inode, struct file *file) +{ + return single_open(file, show_trap_trapped, inode); +} + +static const struct file_operations sel_trap_trapped_ops = { + .open = sel_open_trap_trapped, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void trapped_process_list_refresh(pid_t pid_num) +{ + if (!list_empty(&selinux_trap_process_list_head.list)) { + struct selinux_trap_process_list *entry, *n; + down(&selinux_trap_list_sem); + list_for_each_entry_safe(entry, n, &selinux_trap_process_list_head.list, list) { + if (!find_task_by_vpid(entry->pid) || entry->pid == pid_num) { + /* process not exist or process id hit */ + dget_dlock(entry->ldentry); + d_delete(entry->ldentry); + simple_unlink(entry->inode, entry->ldentry); + dput(entry->ldentry); + sel_trap_process_list_entry_clear(entry); + } + } + up(&selinux_trap_list_sem); + } +} + +static int trapped_pid_entry(pid_t pid_num, char *msg) +{ + struct inode *inode; + struct dentry *ldentry; + char pid_name_buf[10]; /* PID name */ + + snprintf(pid_name_buf, sizeof(pid_name_buf), "%d", pid_num); + + ldentry = d_alloc_name(trapped_dentry, pid_name_buf); + if (!ldentry) + return -ENOMEM; + + inode = sel_make_inode(trapped_dentry->d_sb, S_IFREG|S_IRUGO); + if (!inode) + return -ENOMEM; + + inode->i_fop = &sel_trap_trapped_ops; + inode->i_ino = pid_num; + d_add(ldentry, inode); + + sel_trap_process_list_entry(pid_num, msg, inode, ldentry); + + return 0 ; +} + +void trapped_node_entry(pid_t pid_num, char *msg) +{ + trapped_process_list_refresh(pid_num); + trapped_pid_entry(pid_num, msg); +} + +#endif /* CONFIG_SECURITY_SELINUX_TRAP */ + static int sel_make_avc_files(struct dentry *dir) { int i; @@ -1802,6 +2280,18 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) if (ret) goto err; +#ifdef CONFIG_SECURITY_SELINUX_TRAP + dentry = sel_make_dir(sb->s_root, "trap", &sel_last_ino); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto err; + } + + ret = sel_make_trap_files(dentry); + if (ret) + goto err; +#endif + dentry = sel_make_dir(sb->s_root, "initial_contexts", &sel_last_ino); if (IS_ERR(dentry)) { ret = PTR_ERR(dentry); diff --git a/security/selinux/trap.c b/security/selinux/trap.c new file mode 100644 index 0000000000000000000000000000000000000000..f151d0463c9dea9cf74d7a55f00baf9ae3032a3d --- /dev/null +++ b/security/selinux/trap.c @@ -0,0 +1,866 @@ +/* + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include "avc_ss.h" +#include "trap.h" + +extern void trapped_node_entry(pid_t, char *); + +#define STRING_ALL_LEN_MAX PATH_MAX +#define STRING_PART_LEN_MAX PATH_MAX + +enum string_lsm_audit_data { + STRING_LSM_AUDIT_DATA_TERM = 0, + STRING_LSM_AUDIT_DATA_ACTION, + STRING_LSM_AUDIT_DATA_PID, + STRING_LSM_AUDIT_DATA_NONE, + STRING_LSM_AUDIT_DATA_IPC, + STRING_LSM_AUDIT_DATA_CAP, + STRING_LSM_AUDIT_DATA_PATH, + STRING_LSM_AUDIT_DATA_DENTRY, + STRING_LSM_AUDIT_DATA_INODE, + STRING_LSM_AUDIT_DATA_TASK, + STRING_LSM_AUDIT_DATA_NET, + STRING_LSM_AUDIT_DATA_KEY, + STRING_LSM_AUDIT_DATA_KMOD, + STRING_LSM_AUDIT_DATA_TCONTEXT, + STRING_LSM_AUDIT_DATA_SCONTEXT, + STRING_LSM_AUDIT_DATA_TCLASS, + STRING_LSM_AUDIT_DATA_PERMISSIVE, + STRING_LSM_AUDIT_DATA_MAX +}; + +struct _trapwork { + struct work_struct work; + struct task_struct *task; +}; + +int selinux_trap_enable; +int selinux_trap_debug; +struct selinux_trap_list selinux_trap_list_head; +struct selinux_trap_process_list selinux_trap_process_list_head; +struct semaphore selinux_trap_list_sem; +static char string_work[STRING_PART_LEN_MAX]; +static const char copy_table[] = { + STRING_LSM_AUDIT_DATA_ACTION, /* action */ + STRING_LSM_AUDIT_DATA_PID, /* pid comm */ + STRING_LSM_AUDIT_DATA_INODE, /* name dev ino */ + STRING_LSM_AUDIT_DATA_TCONTEXT, /* scontext */ + STRING_LSM_AUDIT_DATA_SCONTEXT, /* tcontext */ + STRING_LSM_AUDIT_DATA_TCLASS, /* tclass */ + STRING_LSM_AUDIT_DATA_PERMISSIVE, /* permissive ppid pgid pgcomm */ + STRING_LSM_AUDIT_DATA_TERM /* TERM */ +}; + +static int cmp_string(char *rule_str, const char *cmp_str, size_t len) +{ + size_t rule_str_len = strlen(rule_str); + if (rule_str[rule_str_len-1] == '*') + return strncmp(rule_str, cmp_str, rule_str_len-1); /* Wild card match ex) cmpStr = "*" , "xxxxx*" or etc... */ + return strncmp(rule_str, cmp_str, len); /* Exact match ex) ruleStr = "xxxxx" cmpStr ="xxxxx" */ +} + +/* return 0 = identical / not 0 = different */ +static int cmp_polarity(char *rule, int c) +{ + int rc; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for name\n"); + return 1; /* Only + or - string / not NULL */ + } + + trap_devel_log("SELinux: trap: compare rule '%s' with polarity '%c'\n", + rule, c); + + if (rule[0] == c) + rc = 0; /* Matched */ + else + rc = 1; /* Unmatched */ + + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + return rc; +} + +/* return 0 = identical / not 0 = different */ +static int cmp_scontext(char *rule, struct common_audit_data *ad) +{ + int rc; + char *scontext; + u32 scontext_len; + u32 ssid = ad->selinux_audit_data->ssid; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for scontext\n"); + return 0; + } + rc = security_sid_to_context(ssid, &scontext, &scontext_len); + if (rc) { + pr_err("SELinux: trap: error context for ssid:%d\n", + ssid); + return 0; + } + + trap_devel_log("SELinux: trap: compare rule '%s' with scontext '%s'\n", + rule, scontext); + + rc = cmp_string(rule, scontext, scontext_len); + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + kfree(scontext); + return rc; +} + +/* return 0 = identical / not 0 = different */ +static int cmp_tcontext(char *rule, struct common_audit_data *ad) +{ + int rc; + char *tcontext; + u32 tcontext_len; + u32 tsid = ad->selinux_audit_data->tsid; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for tcontext\n"); + return 0; + } + + rc = security_sid_to_context(tsid, &tcontext, &tcontext_len); + if (rc) { + pr_err("SELinux: trap: error context for tsid:%d\n", + tsid); + return 0; + } + + trap_devel_log("SELinux: trap: compare rule '%s' with tcontext '%s'\n", + rule, tcontext); + + rc = cmp_string(rule, tcontext, tcontext_len); + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + kfree(tcontext); + return rc; +} + +/* return 0 = identical / not 0 = different */ +static int cmp_tclass(char *rule, struct common_audit_data *ad) +{ + int rc; + u16 tclass = ad->selinux_audit_data->tclass; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for tclass\n"); + return 0; + } + + BUG_ON(tclass >= secclass_map_size); + + trap_devel_log("SELinux: trap: compare rule '%s' with tclass '%s'\n", + rule, secclass_map[tclass-1].name); + + rc = cmp_string(rule, secclass_map[tclass-1].name, + strlen(secclass_map[tclass-1].name)); + + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + return rc; +} + +/* return 0 = identical / not 0 = different */ +static int get_pname(struct task_struct *task, char *zeroed_page) +{ + int res = 0; + unsigned int arg_len; + struct mm_struct *mm = get_task_mm(task); + if (!mm) + return res; + if (!mm->arg_end) { + mmput(mm); + return res; + } + if (!down_read_trylock(&mm->mmap_sem)) { + mmput(mm); + return res; + } + arg_len = mm->arg_end - mm->arg_start; + + if (arg_len >= PAGE_SIZE) + arg_len = PAGE_SIZE-1; + + res = access_process_vm(task, mm->arg_start, zeroed_page, arg_len, 0); + + up_read(&mm->mmap_sem); + mmput(mm); + return res; +} + +/* return 0 = identical / not 0 = different */ +static int cmp_pname(char *rule, struct common_audit_data *ad) +{ + int rc; + char *pname = NULL; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for pname\n"); + return 0; + } + + pname = (char *)get_zeroed_page(GFP_KERNEL); + if (!pname) { + pr_err("SELinux: trap: get_zeroed_page failed\n"); + return 0; + } + + rcu_read_lock(); + rc = get_pname(current, pname); + rcu_read_unlock(); + + if (rc <= 0) { + pr_err("SELinux: trap: get_pname failed\n"); + free_page((unsigned long) pname); + return 0; + } + + trap_devel_log("SELinux: trap: compare rule '%s' with pname '%s'\n", + rule, pname); + + rc = cmp_string(rule, current->comm, strlen(current->comm)); + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + free_page((unsigned long) pname); + return rc; +} + +/* return 0 = identical / not 0 = different */ +static int cmp_pname_parent(char *rule, struct common_audit_data *ad) +{ + int rc; + char *pname = NULL; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for pname_parent\n"); + return 0; + } + + pname = (char *)get_zeroed_page(GFP_KERNEL); + if (!pname) { + pr_err("SELinux: trap: get_zeroed_page failed\n"); + return 0; + } + + rcu_read_lock(); + rc = get_pname(current->parent, pname); + rcu_read_unlock(); + + if (rc <= 0) { + pr_err("SELinux: trap: get_pname failed\n"); + free_page((unsigned long) pname); + return 0; + } + + trap_devel_log("SELinux: trap: compare rule '%s' with pname_parent '%s'\n", + rule, pname); + + rc = cmp_string(rule, current->comm, strlen(current->comm)); + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + free_page((unsigned long) pname); + return rc; +} + +# if 0 /* XXX: temporarily disabled to check process group leader */ +/* return 0 = identical / not 0 = different */ +static int cmp_pname_pgl(char *rule, struct common_audit_data *ad) +{ + int rc; + char *pname = NULL; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for pname_pgl\n"); + return 0; + } + + pname = (char *)get_zeroed_page(GFP_KERNEL); + if (!pname) { + pr_err("SELinux: trap: get_zeroed_page failed\n"); + return 0; + } + + + rcu_read_lock(); + if (current->group_leader->pid != current->pid) { + rc = get_pname(current->group_leader, pname); + } else { + rc = get_pname(current->parent->group_leader, pname); + } + rcu_read_unlock(); + + if (rc <= 0) { + pr_err("SELinux: trap: get_pname failed\n"); + free_page((unsigned long) pname); + return 0; + } + + trap_devel_log("SELinux: trap: compare rule '%s' with pname_pgl '%s'\n", + rule, pname); + + rc = cmp_string(rule, current->comm, strlen(current->comm)); + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + free_page((unsigned long) pname); + return rc; +} +#endif + +/* return 0 = identical / not 0 = different */ +static int cmp_path(char *rule, struct common_audit_data *ad) +{ + int rc; + struct path *path = &ad->u.path; + char *path_str, *pathname; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for path\n"); + return 0; + } + + if (ad->type != LSM_AUDIT_DATA_PATH) { + trap_devel_log("SELinux: trap: not support for path\n"); + return 0; + } + + pathname = kzalloc(PATH_MAX+11, GFP_KERNEL); + if (!pathname) { + pr_err("SELinux: trap: kzalloc failed\n"); + return 0; + } + + path_str = d_path(path, pathname, PATH_MAX+11); + if (IS_ERR(path_str)) { + kfree(pathname); + pathname = NULL; + pr_err("SELinux: trap: too long path name\n"); + return 0; + } + + trap_devel_log("SELinux: trap: compare rule '%s' with path '%s'\n", + rule, path_str); + + rc = cmp_string(rule, path_str, strlen(path_str)); + + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + kfree(pathname); + pathname = NULL; + return rc; +} + +/* return 0 = identical / not 0 = different */ +static int cmp_name(char *rule, struct common_audit_data *ad) +{ + int rc; + const char *name; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for name\n"); + return 0; + } + + if (ad->type != LSM_AUDIT_DATA_DENTRY) { + trap_devel_log("SELinux: trap: not support for name\n"); + return 0; + } + + name = ad->u.dentry->d_name.name; + + trap_devel_log("SELinux: trap: compare rule '%s' with name '%s'\n", + rule, name); + + rc = cmp_string(rule, name, strlen(name)); + + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + return rc; +} + +/* return 0 = identical / not 0 = different */ +static int cmp_action(char *rule, struct common_audit_data *ad) +{ + int rc; + const char **perms; + int i, perm; + u16 tclass = ad->selinux_audit_data->tclass; + u32 av = ad->selinux_audit_data->audited; + u32 av_rule = 0; + char *temp; + char *token; + + if (!rule) { + trap_devel_log("SELinux: trap: no rule for action\n"); + return 0; + } + + if (av == 0) + return 0; + + temp = kmalloc(strlen(rule)+1, GFP_KERNEL); + if (!temp) { + pr_err("SELinux: trap: kzalloc failed\n"); + return 0; + } + strlcpy(temp, rule, strlen(rule)+1); + + trap_devel_log("SELinux: trap: compare rule '%s' with action [", + rule); + + perms = secclass_map[tclass-1].perms; + + i = 0; + perm = 1; + while (i < (sizeof(av) * 8)) { + if ((perm & av) && perms[i]) + trap_devel_log("%s", perms[i]); + i++; + perm <<= 1; + } + trap_devel_log("]\n"); + + while ((token = strsep(&temp, " ")) != NULL) { + int len = strlen(token); + if (len > 0) { + i = 0; + while (perms[i]) { + trap_devel_log("compare %s - %s\n", token, perms[i]); + if (!strcmp(token, perms[i])) { + trap_devel_log("match\n"); + av_rule |= (1 << i); + break; + } + i++; + } + } + } + kfree(temp); + + trap_devel_log("av 0x%x\n", av); /* audited value */ + trap_devel_log("av_rule 0x%x\n", av_rule); /* result: string matched position */ + + rc = av & ~av_rule; + if (rc) + trap_devel_log("SELinux: trap: different\n"); + else + trap_devel_log("SELinux: trap: identical\n"); + + return rc; +} + +/* param in ad ... check item */ +/* return 0 = blacklist matched or alllist unmatched / 1 = whitelist matched */ +static int mask_trap(struct common_audit_data *ad) +{ + int ret = 0; + struct selinux_trap_list *entry; + rcu_read_lock(); + /* Blacklist matching */ + list_for_each_entry_rcu(entry, &selinux_trap_list_head.list, list) { + if (cmp_polarity( + entry->item_array[TRAP_MASK_TYPE_POLARITY], + '-')) + continue; /* different to next rule */ + else if (cmp_scontext( + entry->item_array[TRAP_MASK_TYPE_SCONTEXT], + ad)) + continue; /* different to next rule */ + else if (cmp_tcontext( + entry->item_array[TRAP_MASK_TYPE_TCONTEXT], + ad)) + continue; /* different to next rule */ + else if (cmp_tclass( + entry->item_array[TRAP_MASK_TYPE_TCLASS], + ad)) + continue; /* different to next rule */ + else if (cmp_pname(entry->item_array[TRAP_MASK_TYPE_PNAME], ad)) + continue; /* different to next rule */ + else if (cmp_pname_parent( + entry->item_array[TRAP_MASK_TYPE_PNAME_PARENT], + ad)) + continue; /* different to next rule */ +#if 0 /* XXX: temporarily disabled to check process group leader */ + else if (cmp_pname_pgl( + entry->item_array[TRAP_MASK_TYPE_PNAME_PGL], + ad)) + continue; /* different to next rule */ +#endif + else if (cmp_path( + entry->item_array[TRAP_MASK_TYPE_PATH], + ad)) + continue; /* different to next rule */ + else if (cmp_name( + entry->item_array[TRAP_MASK_TYPE_NAME], + ad)) + continue; /* different to next rule */ + else if (cmp_action( + entry->item_array[TRAP_MASK_TYPE_ACTION], + ad)) + continue; /* different to next rule */ + /* Rule matched. It requires forcible crash. */ + ret = 0; + goto out; + } + /* Whitelist matching */ + list_for_each_entry_rcu(entry, &selinux_trap_list_head.list, list) { + if (cmp_polarity( + entry->item_array[TRAP_MASK_TYPE_POLARITY], + '+')) + continue; /* different to next rule */ + else if (cmp_scontext( + entry->item_array[TRAP_MASK_TYPE_SCONTEXT], + ad)) + continue; /* different to next rule */ + else if (cmp_tcontext( + entry->item_array[TRAP_MASK_TYPE_TCONTEXT], + ad)) + continue; /* different to next rule */ + else if (cmp_tclass( + entry->item_array[TRAP_MASK_TYPE_TCLASS], + ad)) + continue; /* different to next rule */ + else if (cmp_pname(entry->item_array[TRAP_MASK_TYPE_PNAME], ad)) + continue; /* different to next rule */ + else if (cmp_pname_parent( + entry->item_array[TRAP_MASK_TYPE_PNAME_PARENT], + ad)) + continue; /* different to next rule */ +#if 0 /* XXX: temporarily disabled to check process group leader */ + else if (cmp_pname_pgl( + entry->item_array[TRAP_MASK_TYPE_PNAME_PGL], + ad)) + continue; /* different to next rule */ +#endif + else if (cmp_path( + entry->item_array[TRAP_MASK_TYPE_PATH], + ad)) + continue; /* different to next rule */ + else if (cmp_name( + entry->item_array[TRAP_MASK_TYPE_NAME], + ad)) + continue; /* different to next rule */ + else if (cmp_action( + entry->item_array[TRAP_MASK_TYPE_ACTION], + ad)) + continue; /* different to next rule */ + /* Rule matched. It's exception. */ + ret = 1; + goto out; + } + /* All list not matched ..."ret = 0" */ +out: + rcu_read_unlock(); + return ret; +} + +static void task_killer(struct work_struct *param) +{ + int ret; + struct siginfo info; + struct _trapwork *work = (struct _trapwork *)param; + + memset(&info, 0, sizeof(struct siginfo)); + info.si_signo = SIGABRT; + info.si_code = SI_KERNEL; + pr_info("SELinux: trap: send signal to pid:%d.\n", + work->task->pid); + ret = send_sig_info(SIGABRT, &info, work->task); + if (ret < 0) + pr_err("SELinux: trap: send_sig_info failed\n"); +} + +static void dump_common_audit_data_part(struct common_audit_data *ad, char type, char string[], int len, int maxlen) +{ + struct task_struct *tsk = current; + + /* string work Initialize */ + string_work[0] = '\0'; + + switch (type) { + case STRING_LSM_AUDIT_DATA_ACTION: { + const char **perms; + int i, perm; + u16 tclass = ad->selinux_audit_data->tclass; + u32 av = ad->selinux_audit_data->audited; + + if (av == 0) + break; + perms = secclass_map[tclass-1].perms; + i = 0; + perm = 1; + while (i < (sizeof(av) * 8)) { + if ((perm & av) && perms[i]) + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " { %s }", perms[i]); + i++; + perm <<= 1; + } + break; + } + case STRING_LSM_AUDIT_DATA_PID: + if (tsk && tsk->pid) { + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " pid=%d comm=\"%s\"", tsk->pid, tsk->comm); + } + break; + case STRING_LSM_AUDIT_DATA_NONE: + break; + case STRING_LSM_AUDIT_DATA_IPC: + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " key=%d ", ad->u.ipc_id); + break; + case STRING_LSM_AUDIT_DATA_CAP: + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " capability=%d ", ad->u.cap); + break; + case STRING_LSM_AUDIT_DATA_PATH: { + struct inode *inode; + if (ad->type != LSM_AUDIT_DATA_PATH) + break; + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " path=%s", ad->u.path.dentry->d_iname); + inode = ad->u.path.dentry->d_inode; + if (inode) { + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " dev=\"%s\"", inode->i_sb->s_id); + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " ino=%lu", inode->i_ino); + } + break; + } + case STRING_LSM_AUDIT_DATA_DENTRY: { + struct inode *inode; + if (ad->type != LSM_AUDIT_DATA_DENTRY) + break; + snprintf(string_work, STRING_PART_LEN_MAX, " name=%s", ad->u.dentry->d_name.name); + inode = ad->u.dentry->d_inode; + if (inode) { + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " dev=\"%s\"", inode->i_sb->s_id); + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " ino=%lu", inode->i_ino); + } + break; + } + case STRING_LSM_AUDIT_DATA_INODE: + break; + + case STRING_LSM_AUDIT_DATA_TASK: + tsk = ad->u.tsk; + if (tsk && tsk->pid) { + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " pid=%d comm=\"%s\"", tsk->pid, tsk->comm); + } + break; + case STRING_LSM_AUDIT_DATA_NET: + break; +#ifdef CONFIG_KEYS + case STRING_LSM_AUDIT_DATA_KEY: + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " key_serial=%u", ad->u.key_struct.key); + if (ad->u.key_struct.key_desc) { + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " key_desc=%s", ad->u.key_struct.key_desc); + } + break; +#endif + case STRING_LSM_AUDIT_DATA_KMOD: + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " kmod=%s", ad->u.kmod_name); + break; + + case STRING_LSM_AUDIT_DATA_SCONTEXT: { + int rc; + char *scontext; + u32 scontext_len; + u32 ssid = ad->selinux_audit_data->ssid; + rc = security_sid_to_context(ssid, &scontext, &scontext_len); + if (rc) { + break; + } + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " scontext=%s", scontext); + kfree(scontext); + break; + } + case STRING_LSM_AUDIT_DATA_TCONTEXT: { + int rc; + char *tcontext; + u32 tcontext_len; + u32 tsid = ad->selinux_audit_data->tsid; + rc = security_sid_to_context(tsid, &tcontext, &tcontext_len); + if (rc) { + break; + } + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " tcontext=%s", tcontext); + kfree(tcontext); + break; + } + case STRING_LSM_AUDIT_DATA_TCLASS: { + u16 tclass = ad->selinux_audit_data->tclass; + + BUG_ON(tclass >= secclass_map_size); + + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " tclass=%s", secclass_map[tclass-1].name); + break; + } + case STRING_LSM_AUDIT_DATA_PERMISSIVE: + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " permissive=%u", ad->selinux_audit_data->result ? 0 : 1); + if (tsk && tsk->pid) { + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " ppid=%d pcomm=\"%s\"", tsk->parent->pid, tsk->parent->comm); + if (tsk->group_leader->pid != tsk->pid) { + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " pgid=%d pgcomm=\"%s\"", tsk->group_leader->pid, tsk->group_leader->comm); + } else if (tsk->parent->group_leader->pid) { + snprintf(&string_work[strlen(string_work)], STRING_PART_LEN_MAX-strlen(string_work), " pgid=%d pgcomm=\"%s\"", tsk->parent->group_leader->pid, tsk->parent->group_leader->comm); + } + } + break; + } /* switch (ad->type) */ + /* parent buff size check */ + if (strlen(string_work) < maxlen - len) { + /* parent buff copy */ + strlcpy(&string[len], string_work, maxlen - len); + } +} + +static char *dump_audit_data(struct common_audit_data *ad) +{ + char *string = NULL; + int i; + + string = kmalloc(STRING_ALL_LEN_MAX, GFP_KERNEL); + if (!string) { + /* error */ + return NULL; + } + + /* string work Initialize */ + string[0] = '\0'; + + for (i = 0; STRING_LSM_AUDIT_DATA_TERM != copy_table[i]; i++) { + dump_common_audit_data_part(ad, copy_table[i], string, strlen(string), STRING_ALL_LEN_MAX); + } + return string; +} + +static void trapped_node_update(struct common_audit_data *ad) +{ + char *string = NULL; + struct task_struct *tsk = current; + + rcu_read_lock(); + + string = dump_audit_data(ad); + if (string) { + /* kmsg output */ + pr_info("SELinux: trap: caught%s", string); + /* Node Entry */ + trapped_node_entry(tsk->pid, string); + } + + rcu_read_unlock(); +} + +void trap_selinux_error(struct common_audit_data *ad) +{ + int ret; + struct _trapwork *work; + + if (!selinux_trap_enable) + return; + + /* black list and white list check */ + if (mask_trap(ad)) { + /* Ignore error type( No problem ) */ + if (selinux_trap_debug >= TRAP_LOGLEVEL_NORMAL) { + pr_info("SELinux: trap: Ignore SELinux violation(pid = %d).\n", ((struct task_struct *)current)->pid); + } + return; + } + + /* trapped Update & kmeg */ + trapped_node_update(ad); + + /* Violation( process Abort ) */ + work = kmalloc(sizeof(struct _trapwork), GFP_KERNEL); + if (work) { + INIT_WORK((struct work_struct *)work, task_killer); + work->task = current; + ret = schedule_work((struct work_struct *)work); + if (!ret) + pr_err("SELinux: trap: schedule_work failed\n"); + + pr_info("SELinux: trap: block process.\n"); + flush_work((struct work_struct *)work); + pr_info("SELinux: trap: show stack.\n"); + show_stack(work->task, NULL); + pr_info("SELinux: trap: process came back.\n"); + } else { + pr_err("SELinux: trap: kmalloc() failed\n"); + } + kfree((void *)work); +} + +static int selinux_trap_init(void) +{ + int ret = 0; + selinux_trap_debug = TRAP_LOGLEVEL_NORMAL; + trap_devel_log("SELinux: trap: Init module\n"); + sema_init(&selinux_trap_list_sem, 1); + INIT_LIST_HEAD(&selinux_trap_list_head.list); + INIT_LIST_HEAD(&selinux_trap_process_list_head.list); + return ret; +} + +static void selinux_trap_exit(void) +{ + trap_devel_log("SELinux: trap: Exit module\n"); +} + +module_init(selinux_trap_init); +module_exit(selinux_trap_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Naoya Hirota "); +MODULE_AUTHOR("Naoya Inoue "); +MODULE_DESCRIPTION("SELinux error trap extention"); diff --git a/sound/core/info.c b/sound/core/info.c index a04016c19f6dfb67907bf54b67ea0f877e1050df..79dee33b5035623caf1e1b8f88570e777b865a73 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -754,11 +754,8 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent) INIT_LIST_HEAD(&entry->children); INIT_LIST_HEAD(&entry->list); entry->parent = parent; - if (parent) { - mutex_lock(&parent->access); + if (parent) list_add_tail(&entry->list, &parent->children); - mutex_unlock(&parent->access); - } return entry; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 9af294c72a4d108d502fbc6979118ec1cee193b4..1f062aaa5414a5c122b6d542467ac010eda453ee 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -654,9 +654,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) if (substream->ops->hw_free) result = substream->ops->hw_free(substream); snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); - if (pm_qos_request_active(&substream->latency_pm_qos_req)) - pm_qos_remove_request(&substream->latency_pm_qos_req); - + pm_qos_remove_request(&substream->latency_pm_qos_req); return result; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 776dffa88aee41a7a61a74eb702e0eae067e1649..373fcad840ea6ff5c18b4c4aa93b6473c7a60f1c 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -294,8 +294,6 @@ struct hda_codec { #define list_for_each_codec(c, bus) \ list_for_each_entry(c, &(bus)->core.codec_list, core.list) -#define list_for_each_codec_safe(c, n, bus) \ - list_for_each_entry_safe(c, n, &(bus)->core.codec_list, core.list) /* snd_hda_codec_read/write optional flags */ #define HDA_RW_NO_RESPONSE_FALLBACK (1 << 0) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 9c6e10fb479f4278fd710eb5af212e798de40b7e..5baf8b56b6e7604637bca89eae54ca63ce4e6232 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1128,12 +1128,8 @@ EXPORT_SYMBOL_GPL(azx_probe_codecs); /* configure each codec instance */ int azx_codec_configure(struct azx *chip) { - struct hda_codec *codec, *next; - - /* use _safe version here since snd_hda_codec_configure() deregisters - * the device upon error and deletes itself from the bus list. - */ - list_for_each_codec_safe(codec, next, &chip->bus) { + struct hda_codec *codec; + list_for_each_codec(codec, &chip->bus) { snd_hda_codec_configure(codec); } return 0; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 689df78f640a41d368beb03bde29fd34a88b257c..dc2fa576d60d0c343278e9eeba881a732e653557 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3190,7 +3190,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec) spec->input_paths[i][nums]); spec->input_paths[i][nums] = spec->input_paths[i][n]; - spec->input_paths[i][n] = 0; } } nums++; diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c index 58df020811f16c253225e046d7a4644404d6dc58..b91d13c8e010868bcdf8f3d5fd5199e3e4126ace 100644 --- a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c +++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c @@ -1039,6 +1039,7 @@ static int msm_sdw_swrm_read(void *handle, int reg) __func__, reg); sdw_rd_addr_base = MSM_SDW_AHB_BRIDGE_RD_ADDR_0; sdw_rd_data_base = MSM_SDW_AHB_BRIDGE_RD_DATA_0; + /* * Add sleep as SWR slave access read takes time. * Allow for RD_DONE to complete for previous register if any. @@ -1053,8 +1054,6 @@ static int msm_sdw_swrm_read(void *handle, int reg) dev_err(msm_sdw->dev, "%s: RD Addr Failure\n", __func__); goto err; } - /* Add sleep for SWR register read value to get updated. */ - usleep_range(100, 105); /* Check for RD value */ ret = regmap_bulk_read(msm_sdw->regmap, sdw_rd_data_base, (u8 *)&val, 4); @@ -1080,12 +1079,12 @@ static int msm_sdw_bulk_write(struct msm_sdw_priv *msm_sdw, sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0; sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0; + /* + * Add sleep as SWR slave write takes time. + * Allow for any previous pending write to complete. + */ + usleep_range(50, 55); for (i = 0; i < len; i += 2) { - /* - * Add sleep as SWR slave write takes time. - * Allow for any previous pending write to complete. - */ - usleep_range(100, 105); /* First Write the Data to register */ ret = regmap_bulk_write(msm_sdw->regmap, sdw_wr_data_base, bulk_reg[i].buf, 4); diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c index 58de3c5fbff125574a1ea490fd4c9f4cb7d64a7c..025a592b40155547c2d47501c2c9afd278c48eac 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -49,10 +49,10 @@ #define BUS_DOWN 1 /* - * 200 Milliseconds sufficient for DSP bring up in the lpass + * 50 Milliseconds sufficient for DSP bring up in the lpass * after Sub System Restart */ -#define ADSP_STATE_READY_TIMEOUT_MS 200 +#define ADSP_STATE_READY_TIMEOUT_MS 50 #define EAR_PMD 0 #define EAR_PMU 1 @@ -2619,17 +2619,6 @@ static int msm_anlg_cdc_codec_enable_micbias(struct snd_soc_dapm_widget *w, return 0; } -static void set_compander_mode(void *handle, int val) -{ - struct sdm660_cdc_priv *handle_cdc = handle; - struct snd_soc_codec *codec = handle_cdc->codec; - - if (get_codec_version(handle_cdc) >= DIANGU) { - snd_soc_update_bits(codec, - MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, - 0x08, val); - }; -} static void update_clkdiv(void *handle, int val) { struct sdm660_cdc_priv *handle_cdc = handle; @@ -4660,7 +4649,6 @@ static int msm_anlg_cdc_probe(struct platform_device *pdev) BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier_mbhc); sdm660_cdc->dig_plat_data.handle = (void *) sdm660_cdc; - sdm660_cdc->dig_plat_data.set_compander_mode = set_compander_mode; sdm660_cdc->dig_plat_data.update_clkdiv = update_clkdiv; sdm660_cdc->dig_plat_data.get_cdc_version = get_cdc_version; sdm660_cdc->dig_plat_data.register_notifier = diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h index d07d1bee4d6b7f77f7f7bdf988aed184bcb427da..9563565f36d215bb2c4df85a434fe1a51626089f 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h @@ -168,7 +168,6 @@ struct msm_dig_ctrl_data { struct msm_dig_ctrl_platform_data { void *handle; - void (*set_compander_mode)(void *handle, int val); void (*update_clkdiv)(void *handle, int val); int (*get_cdc_version)(void *handle); int (*register_notifier)(void *handle, diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index 95aa0440f72dd10720f10eed73b6385e62122402..4249ada17c87cdb1d1c8c6d8f6c73a9042fb4b58 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -214,92 +214,60 @@ static int msm_dig_cdc_codec_config_compander(struct snd_soc_codec *codec, int interp_n, int event) { struct msm_dig_priv *dig_cdc = snd_soc_codec_get_drvdata(codec); - int comp_ch_bits_set = 0x03; - int comp_ch_value; dev_dbg(codec->dev, "%s: event %d shift %d, enabled %d\n", __func__, event, interp_n, dig_cdc->comp_enabled[interp_n]); - /* compander is invalid */ - if (dig_cdc->comp_enabled[interp_n] != COMPANDER_1 && - dig_cdc->comp_enabled[interp_n]) { - dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__, - dig_cdc->comp_enabled[interp_n]); + /* compander is not enabled */ + if (!dig_cdc->comp_enabled[interp_n]) return 0; - } - if (SND_SOC_DAPM_EVENT_ON(event)) { - /* compander is not enabled */ - if (!dig_cdc->comp_enabled[interp_n]) { - dig_cdc->set_compander_mode(dig_cdc->handle, 0x00); - return 0; - }; - comp_ch_value = snd_soc_read(codec, - MSM89XX_CDC_CORE_COMP0_B1_CTL); - if (interp_n == 0) { - if ((comp_ch_value & 0x02) == 0x02) { - dev_dbg(codec->dev, - "%s comp ch already enabled\n", - __func__); - return 0; - } - } - if (interp_n == 1) { - if ((comp_ch_value & 0x01) == 0x01) { - dev_dbg(codec->dev, - "%s comp ch already enabled\n", - __func__); - return 0; - } - } - dig_cdc->set_compander_mode(dig_cdc->handle, 0x08); - /* Enable Compander Clock */ - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01); - if (dig_cdc->comp_enabled[MSM89XX_RX1]) { + switch (dig_cdc->comp_enabled[interp_n]) { + case COMPANDER_1: + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B1_CTL, - 0x02, 0x02); - } - if (dig_cdc->comp_enabled[MSM89XX_RX2]) { + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01); snd_soc_update_bits(codec, MSM89XX_CDC_CORE_COMP0_B1_CTL, - 0x01, 0x01); - } - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50); - /* add sleep for compander to settle */ - usleep_range(1000, 1100); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0); + 1 << interp_n, 1 << interp_n); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50); + /* add sleep for compander to settle */ + usleep_range(1000, 1100); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28); + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0); - /* Enable Compander GPIO */ - if (dig_cdc->codec_hph_comp_gpio) - dig_cdc->codec_hph_comp_gpio(1, codec); - } else if (SND_SOC_DAPM_EVENT_OFF(event)) { - /* Disable Compander GPIO */ - if (dig_cdc->codec_hph_comp_gpio) - dig_cdc->codec_hph_comp_gpio(0, codec); + /* Enable Compander GPIO */ + if (dig_cdc->codec_hph_comp_gpio) + dig_cdc->codec_hph_comp_gpio(1, codec); + } else if (SND_SOC_DAPM_EVENT_OFF(event)) { + /* Disable Compander GPIO */ + if (dig_cdc->codec_hph_comp_gpio) + dig_cdc->codec_hph_comp_gpio(0, codec); - snd_soc_update_bits(codec, - MSM89XX_CDC_CORE_COMP0_B1_CTL, - 1 << interp_n, 0); - comp_ch_bits_set = snd_soc_read(codec, - MSM89XX_CDC_CORE_COMP0_B1_CTL); - if ((comp_ch_bits_set & 0x03) == 0x00) { snd_soc_update_bits(codec, MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x05); - snd_soc_update_bits(codec, + snd_soc_update_bits(codec, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 1 << interp_n, 0); + snd_soc_update_bits(codec, MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x00); } - } + break; + default: + dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__, + dig_cdc->comp_enabled[interp_n]); + break; + }; + return 0; } @@ -2133,7 +2101,6 @@ static int msm_dig_cdc_probe(struct platform_device *pdev) msm_dig_cdc->dig_base, &msm_digital_regmap_config); msm_dig_cdc->update_clkdiv = pdata->update_clkdiv; - msm_dig_cdc->set_compander_mode = pdata->set_compander_mode; msm_dig_cdc->get_cdc_version = pdata->get_cdc_version; msm_dig_cdc->handle = pdata->handle; msm_dig_cdc->register_notifier = pdata->register_notifier; diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h index 11f36f99f1bda3e8f099fb266df99c6a444056be..f0e7a9cf92283be9790884c5325fffefa3973bc2 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h @@ -49,7 +49,6 @@ struct msm_dig_priv { u32 mute_mask; int dapm_bias_off; void *handle; - void (*set_compander_mode)(void *handle, int val); void (*update_clkdiv)(void *handle, int val); int (*get_cdc_version)(void *handle); int (*register_notifier)(void *handle, @@ -59,7 +58,6 @@ struct msm_dig_priv { struct dig_ctrl_platform_data { void *handle; - void (*set_compander_mode)(void *handle, int val); void (*update_clkdiv)(void *handle, int val); int (*get_cdc_version)(void *handle); int (*register_notifier)(void *handle, diff --git a/sound/soc/codecs/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c index 1613c5baa9c7f5a90b1d8b688cd2f7e4344f1b0a..9b1c8c98946c16cf83757f668a78eea882f29d03 100644 --- a/sound/soc/codecs/wcd-dsp-mgr.c +++ b/sound/soc/codecs/wcd-dsp-mgr.c @@ -415,24 +415,22 @@ static int wdsp_download_segments(struct wdsp_mgr_priv *wdsp, /* Go through the list of segments and download one by one */ list_for_each_entry(seg, wdsp->seg_list, list) { ret = wdsp_load_each_segment(wdsp, seg); - if (ret) + if (IS_ERR_VALUE(ret)) { + wdsp_broadcast_event_downseq(wdsp, + WDSP_EVENT_DLOAD_FAILED, + NULL); goto dload_error; + } } - /* Flush the list before setting status and notifying components */ - wdsp_flush_segment_list(wdsp->seg_list); - WDSP_SET_STATUS(wdsp, status); /* Notify all components that image is downloaded */ wdsp_broadcast_event_downseq(wdsp, post, NULL); -done: - return ret; dload_error: wdsp_flush_segment_list(wdsp->seg_list); - wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_DLOAD_FAILED, NULL); - +done: return ret; } @@ -486,14 +484,10 @@ static int wdsp_enable_dsp(struct wdsp_mgr_priv *wdsp) /* Make sure wdsp is in good state */ if (!WDSP_STATUS_IS_SET(wdsp, WDSP_STATUS_CODE_DLOADED)) { WDSP_ERR(wdsp, "WDSP in invalid state 0x%x", wdsp->status); - return -EINVAL; + ret = -EINVAL; + goto done; } - /* - * Acquire SSR mutex lock to make sure enablement of DSP - * does not race with SSR handling. - */ - WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex); /* Download the read-write sections of image */ ret = wdsp_download_segments(wdsp, WDSP_ELF_FLAG_WRITE); if (IS_ERR_VALUE(ret)) { @@ -514,7 +508,6 @@ static int wdsp_enable_dsp(struct wdsp_mgr_priv *wdsp) wdsp_broadcast_event_downseq(wdsp, WDSP_EVENT_POST_BOOTUP, NULL); WDSP_SET_STATUS(wdsp, WDSP_STATUS_BOOTED); done: - WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex); return ret; } diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 997a623033fbf23b551c44566c1447a436b50ddf..8fd9b600fd8b65d1e1dcb5b414f6c03ccf2edbc0 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -44,17 +49,19 @@ #define SPECIAL_HS_DETECT_TIME_MS (2 * 1000) #define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250 #define GND_MIC_SWAP_THRESHOLD 4 -#define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100 +#define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 150 #define HS_VREF_MIN_VAL 1400 #define FW_READ_ATTEMPTS 15 #define FW_READ_TIMEOUT 4000000 -#define FAKE_REM_RETRY_ATTEMPTS 3 -#define MAX_IMPED 60000 +#define FAKE_REM_RETRY_ATTEMPTS 10 #define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50 #define ANC_DETECT_RETRY_CNT 7 #define WCD_MBHC_SPL_HS_CNT 1 +static bool skip_impdet_retry; +static bool lineout_detected; + static int det_extn_cable_en; module_param(det_extn_cable_en, int, S_IRUGO | S_IWUSR | S_IWGRP); @@ -608,6 +615,7 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, { struct snd_soc_codec *codec = mbhc->codec; bool is_pa_on = false; + bool skip_report = false; WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); @@ -648,7 +656,10 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, } mbhc->hph_type = WCD_MBHC_HPH_NONE; - mbhc->zl = mbhc->zr = 0; + mbhc->extn_cable_inserted = false; + lineout_detected = false; + if (!skip_impdet_retry) + mbhc->zl = mbhc->zr = 0; pr_debug("%s: Reporting removal %d(%x)\n", __func__, jack_type, mbhc->hph_status); wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, @@ -668,8 +679,7 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, jack_type == SND_JACK_LINEOUT) && (mbhc->hph_status && mbhc->hph_status != jack_type)) { - if (mbhc->micbias_enable && - mbhc->hph_status == SND_JACK_HEADSET) { + if (mbhc->micbias_enable) { if (mbhc->mbhc_cb->mbhc_micbias_control) mbhc->mbhc_cb->mbhc_micbias_control( codec, MIC_BIAS_2, @@ -687,7 +697,9 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, mbhc->micbias_enable = false; } mbhc->hph_type = WCD_MBHC_HPH_NONE; - mbhc->zl = mbhc->zr = 0; + lineout_detected = false; + if (!skip_impdet_retry) + mbhc->zl = mbhc->zr = 0; pr_debug("%s: Reporting removal (%x)\n", __func__, mbhc->hph_status); wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, @@ -728,6 +740,8 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, mbhc->jiffies_atreport = jiffies; } else if (jack_type == SND_JACK_LINEOUT) { mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; + skip_report = true; + pr_debug("%s: extension cable detected\n", __func__); } else if (jack_type == SND_JACK_ANC_HEADPHONE) mbhc->current_plug = MBHC_PLUG_TYPE_ANC_HEADPHONE; @@ -738,16 +752,42 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, mbhc->mbhc_cb->compute_impedance && (mbhc->mbhc_cfg->linein_th != 0) && (!is_pa_on)) { + if (!skip_impdet_retry) { mbhc->mbhc_cb->compute_impedance(mbhc, &mbhc->zl, &mbhc->zr); - if ((mbhc->zl > mbhc->mbhc_cfg->linein_th && - mbhc->zl < MAX_IMPED) && - (mbhc->zr > mbhc->mbhc_cfg->linein_th && - mbhc->zr < MAX_IMPED) && - (jack_type == SND_JACK_HEADPHONE)) { + pr_debug("%s: impedance L:%d R:%d\n", __func__, + mbhc->zl, mbhc->zr); + } else { + pr_debug("%s: skip impedance detection\n", + __func__); + } + + if (jack_type == SND_JACK_HEADPHONE) + skip_impdet_retry = true; + else + skip_impdet_retry = false; + + if (mbhc->zl > mbhc->mbhc_cfg->linein_th && + jack_type == SND_JACK_ANC_HEADPHONE) { + if(!wcd_mbhc_is_hph_pa_on(mbhc)) { + jack_type = SND_JACK_STEREO_MICROPHONE; + mbhc->current_plug = + MBHC_PLUG_TYPE_STEREO_MICROPHONE; + mbhc->hph_status &= ~SND_JACK_HEADPHONE; + pr_debug("%s: Stereo microphone detected\n", + __func__); + } else { + pr_debug("%s: Skip Stereo microphone reporting\n", + __func__); + } + } else if (mbhc->zl > mbhc->mbhc_cfg->linein_th && + mbhc->zr > mbhc->mbhc_cfg->linein_th && + jack_type == SND_JACK_HEADPHONE) { jack_type = SND_JACK_LINEOUT; mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; - if (mbhc->hph_status) { + lineout_detected = true; + if (mbhc->hph_status && + mbhc->hph_status != SND_JACK_LINEOUT) { mbhc->hph_status &= ~(SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_UNSUPPORTED); @@ -763,11 +803,16 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, mbhc->hph_status |= jack_type; - pr_debug("%s: Reporting insertion %d(%x)\n", __func__, - jack_type, mbhc->hph_status); - wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, - (mbhc->hph_status | SND_JACK_MECHANICAL), - WCD_MBHC_JACK_MASK); + if (!skip_report) { + pr_debug("%s: Reporting insertion %d(%x)\n", __func__, + jack_type, mbhc->hph_status); + wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, + (mbhc->hph_status | + SND_JACK_MECHANICAL), + WCD_MBHC_JACK_MASK); + } else { + pr_debug("%s: Skip reporting insertion\n", __func__); + } wcd_mbhc_clr_and_turnon_hph_padac(mbhc); } pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status); @@ -1089,6 +1134,7 @@ static void wcd_mbhc_update_fsm_source(struct wcd_mbhc *mbhc, break; case MBHC_PLUG_TYPE_HEADSET: case MBHC_PLUG_TYPE_ANC_HEADPHONE: + case MBHC_PLUG_TYPE_STEREO_MICROPHONE: if (!mbhc->is_hs_recording && !micbias2) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); break; @@ -1211,6 +1257,10 @@ static void wcd_correct_swch_plug(struct work_struct *work) mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); codec = mbhc->codec; + /* Wait for debounce time 200ms for extension cable */ + if (mbhc->extn_cable_inserted) + msleep(200); + /* * Enable micbias/pullup for detection in correct work. * This work will get scheduled from detect_plug_type which @@ -1422,7 +1472,9 @@ correct_plug_type: if (((mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) && (mbhc->current_plug != - MBHC_PLUG_TYPE_ANC_HEADPHONE)) && + MBHC_PLUG_TYPE_ANC_HEADPHONE) && + (mbhc->current_plug != + MBHC_PLUG_TYPE_STEREO_MICROPHONE)) && !wcd_swch_level_remove(mbhc) && !mbhc->btn_press_intr) { pr_debug("%s: cable is %sheadset\n", @@ -1439,21 +1491,25 @@ correct_plug_type: if (!wrk_complete && mbhc->btn_press_intr) { pr_debug("%s: Can be slow insertion of headphone\n", __func__); wcd_cancel_btn_work(mbhc); - plug_type = MBHC_PLUG_TYPE_HEADPHONE; + if (lineout_detected) + plug_type = MBHC_PLUG_TYPE_HIGH_HPH; + else + plug_type = MBHC_PLUG_TYPE_HEADPHONE; } /* * If plug_tye is headset, we might have already reported either in * detect_plug-type or in above while loop, no need to report again */ if (!wrk_complete && ((plug_type == MBHC_PLUG_TYPE_HEADSET) || - (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE))) { + (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE) || + (plug_type == MBHC_PLUG_TYPE_STEREO_MICROPHONE))) { pr_debug("%s: plug_type:0x%x already reported\n", __func__, mbhc->current_plug); goto enable_supply; } if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH && - (!det_extn_cable_en)) { + (!det_extn_cable_en) && (!lineout_detected)) { if (wcd_is_special_headset(mbhc)) { pr_debug("%s: Special headset found %d\n", __func__, plug_type); @@ -1532,6 +1588,8 @@ exit: if (mbhc->mbhc_cb->hph_pull_down_ctrl) mbhc->mbhc_cb->hph_pull_down_ctrl(codec, true); + skip_impdet_retry = false; + mbhc->mbhc_cb->lock_sleep(mbhc, false); pr_debug("%s: leave\n", __func__); } @@ -1685,6 +1743,15 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) 0); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); wcd_mbhc_report_plug(mbhc, 0, SND_JACK_ANC_HEADPHONE); + } else if (mbhc->current_plug == + MBHC_PLUG_TYPE_STEREO_MICROPHONE) { + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, false); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, + 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); + wcd_mbhc_report_plug(mbhc, + 0, SND_JACK_STEREO_MICROPHONE); } } else if (!detection_type) { /* Disable external voltage source to micbias if present */ @@ -1825,6 +1892,7 @@ determine_plug: hphl_trigerred = 0; mic_trigerred = 0; mbhc->is_extn_cable = true; + mbhc->extn_cable_inserted = true; mbhc->btn_press_intr = false; mbhc->is_btn_press = false; wcd_mbhc_detect_plug_type(mbhc); @@ -2831,6 +2899,7 @@ int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec, mbhc->btn_press_intr = false; mbhc->is_hs_recording = false; mbhc->is_extn_cable = false; + mbhc->extn_cable_inserted = false; mbhc->hph_type = WCD_MBHC_HPH_NONE; mbhc->wcd_mbhc_regs = wcd_mbhc_regs; diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h index 09b9307ad61de5de9d85a0fd9b29dec01c08af48..8b53462e364037adb94e3b45d5ea885c458f5cb6 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.h +++ b/sound/soc/codecs/wcd-mbhc-v2.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef __WCD_MBHC_V2_H__ #define __WCD_MBHC_V2_H__ @@ -22,7 +27,7 @@ #define WCD_MBHC_DEF_BUTTONS 8 #define WCD_MBHC_KEYCODE_NUM 8 #define WCD_MBHC_USLEEP_RANGE_MARGIN_US 100 -#define WCD_MBHC_THR_HS_MICB_MV 2700 +#define WCD_MBHC_THR_HS_MICB_MV 2750 /* z value defined in Ohms */ #define WCD_MONO_HS_MIN_THR 2 #define WCD_MBHC_STRINGIFY(s) __stringify(s) @@ -82,6 +87,7 @@ enum wcd_mbhc_plug_type { MBHC_PLUG_TYPE_HIGH_HPH, MBHC_PLUG_TYPE_GND_MIC_SWAP, MBHC_PLUG_TYPE_ANC_HEADPHONE, + MBHC_PLUG_TYPE_STEREO_MICROPHONE, }; enum pa_dac_ack_flags { @@ -423,6 +429,7 @@ struct wcd_mbhc { bool btn_press_intr; bool is_hs_recording; bool is_extn_cable; + bool extn_cable_inserted; bool skip_imped_detection; bool is_btn_already_regd; diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 870818ad801c44bfa0002c582e9031d2992a04f3..013b80bedae72ceae57230607819918349f5e980 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -110,7 +115,7 @@ /* Convert from vout ctl to micbias voltage in mV */ #define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) -#define TASHA_ZDET_NUM_MEASUREMENTS 900 +#define TASHA_ZDET_NUM_MEASUREMENTS 150 #define TASHA_MBHC_GET_C1(c) ((c & 0xC000) >> 14) #define TASHA_MBHC_GET_X1(x) (x & 0x3FFF) /* z value compared in milliOhm */ @@ -869,8 +874,8 @@ static const struct tasha_reg_mask_val tasha_spkr_default[] = { {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80}, {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01}, {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01}, - {WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x50}, - {WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x50}, + {WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x58}, + {WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x58}, }; static const struct tasha_reg_mask_val tasha_spkr_mode1[] = { @@ -1857,7 +1862,7 @@ static inline void tasha_mbhc_get_result_params(struct wcd9xxx *wcd9xxx, if ((c1 < 2) && x1) usleep_range(5000, 5050); - if (!c1 || !x1) { + if (!c1) { dev_dbg(wcd9xxx->dev, "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", __func__, c1, x1); @@ -5227,6 +5232,22 @@ static int tasha_codec_config_ear_spkr_gain(struct snd_soc_codec *codec, return 0; } +static void tasha_codec_set_offset_val(int *offset_val, int gain_offset, + int mult) +{ + switch (gain_offset) { + case RX_GAIN_OFFSET_M0P5_DB: + *offset_val = 1 * mult; + break; + case RX_GAIN_OFFSET_M1P5_DB: + *offset_val = 2 * mult; + break; + default: + pr_err("Improper gain offset\n"); + break; + } +} + static int tasha_codec_enable_mix_path(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -5274,7 +5295,7 @@ static int tasha_codec_enable_mix_path(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) && + if ((tasha->spkr_gain_offset != RX_GAIN_OFFSET_0_DB) && (tasha->comp_enabled[COMPANDER_7] || tasha->comp_enabled[COMPANDER_8]) && (gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL || @@ -5289,7 +5310,8 @@ static int tasha_codec_enable_mix_path(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, 0x01, 0x01); - offset_val = -2; + tasha_codec_set_offset_val(&offset_val, + tasha->spkr_gain_offset, -1); } val = snd_soc_read(codec, gain_reg); val += offset_val; @@ -5297,7 +5319,7 @@ static int tasha_codec_enable_mix_path(struct snd_soc_dapm_widget *w, tasha_codec_config_ear_spkr_gain(codec, event, gain_reg); break; case SND_SOC_DAPM_POST_PMD: - if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) && + if ((tasha->spkr_gain_offset != RX_GAIN_OFFSET_0_DB) && (tasha->comp_enabled[COMPANDER_7] || tasha->comp_enabled[COMPANDER_8]) && (gain_reg == WCD9335_CDC_RX7_RX_VOL_MIX_CTL || @@ -5312,7 +5334,8 @@ static int tasha_codec_enable_mix_path(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, 0x01, 0x00); - offset_val = 2; + tasha_codec_set_offset_val(&offset_val, + tasha->spkr_gain_offset, 1); val = snd_soc_read(codec, gain_reg); val += offset_val; snd_soc_write(codec, gain_reg, val); @@ -5502,7 +5525,7 @@ static int tasha_codec_enable_interpolator(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: tasha_config_compander(codec, w->shift, event); /* apply gain after int clk is enabled */ - if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) && + if ((tasha->spkr_gain_offset != RX_GAIN_OFFSET_0_DB) && (tasha->comp_enabled[COMPANDER_7] || tasha->comp_enabled[COMPANDER_8]) && (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL || @@ -5517,7 +5540,8 @@ static int tasha_codec_enable_interpolator(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, 0x01, 0x01); - offset_val = -2; + tasha_codec_set_offset_val(&offset_val, + tasha->spkr_gain_offset, -1); } val = snd_soc_read(codec, gain_reg); val += offset_val; @@ -5527,7 +5551,7 @@ static int tasha_codec_enable_interpolator(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMD: tasha_config_compander(codec, w->shift, event); tasha_codec_enable_prim_interpolator(codec, reg, event); - if ((tasha->spkr_gain_offset == RX_GAIN_OFFSET_M1P5_DB) && + if ((tasha->spkr_gain_offset != RX_GAIN_OFFSET_0_DB) && (tasha->comp_enabled[COMPANDER_7] || tasha->comp_enabled[COMPANDER_8]) && (gain_reg == WCD9335_CDC_RX7_RX_VOL_CTL || @@ -5542,7 +5566,8 @@ static int tasha_codec_enable_interpolator(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, 0x01, 0x00); - offset_val = 2; + tasha_codec_set_offset_val(&offset_val, + tasha->spkr_gain_offset, 1); val = snd_soc_read(codec, gain_reg); val += offset_val; snd_soc_write(codec, gain_reg, val); @@ -12127,10 +12152,8 @@ static int tasha_dig_core_power_collapse(struct tasha_priv *tasha, goto unlock_mutex; if (tasha->power_active_ref < 0) { - dev_info(tasha->dev, - "%s: power_active_ref is negative, resetting it\n", + dev_dbg(tasha->dev, "%s: power_active_ref is negative\n", __func__); - tasha->power_active_ref = 0; goto unlock_mutex; } @@ -12519,8 +12542,8 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_common_val[] = { {WCD9335_CDC_CLSH_K2_MSB, 0x0F, 0x00}, {WCD9335_CDC_CLSH_K2_LSB, 0xFF, 0x60}, {WCD9335_CPE_SS_DMIC_CFG, 0x80, 0x00}, - {WCD9335_CDC_BOOST0_BOOST_CTL, 0x70, 0x50}, - {WCD9335_CDC_BOOST1_BOOST_CTL, 0x70, 0x50}, + {WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x58}, + {WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x58}, {WCD9335_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08}, {WCD9335_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08}, {WCD9335_ANA_LO_1_2, 0x3C, 0X3C}, @@ -13600,7 +13623,7 @@ static int tasha_codec_probe(struct snd_soc_codec *codec) for (i = 0; i < COMPANDER_MAX; i++) tasha->comp_enabled[i] = 0; - tasha->spkr_gain_offset = RX_GAIN_OFFSET_0_DB; + tasha->spkr_gain_offset = RX_GAIN_OFFSET_M0P5_DB; tasha->intf_type = wcd9xxx_get_intf_type(); tasha_update_reg_reset_values(codec); pr_debug("%s: MCLK Rate = %x\n", __func__, control->mclk_rate); diff --git a/sound/soc/codecs/wcd9335.h b/sound/soc/codecs/wcd9335.h index 8d38399ba92f04c150b35fea6134ada48b35dc2f..f028f0526f53bf1c9b7ba2454239d0ed60addf59 100644 --- a/sound/soc/codecs/wcd9335.h +++ b/sound/soc/codecs/wcd9335.h @@ -172,6 +172,7 @@ enum { */ enum { RX_GAIN_OFFSET_M1P5_DB, + RX_GAIN_OFFSET_M0P5_DB, RX_GAIN_OFFSET_0_DB, }; diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c index 29c218013a07b1ba96faf262e115ed9e7dda40d4..e791bf07ec67272c5f541606062742ce4b30b769 100644 --- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c +++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c @@ -763,6 +763,10 @@ static int wcd_control_handler(struct device *dev, void *priv_data, case WDSP_EVENT_DLOAD_FAILED: case WDSP_EVENT_POST_SHUTDOWN: + if (event == WDSP_EVENT_POST_DLOAD_CODE) + /* Mark DSP online since code download is complete */ + wcd_cntl_change_online_state(cntl, 1); + /* Disable CPAR */ wcd_cntl_cpar_ctrl(cntl, false); /* Disable all the clocks */ @@ -771,11 +775,6 @@ static int wcd_control_handler(struct device *dev, void *priv_data, dev_err(codec->dev, "%s: Failed to disable clocks, err = %d\n", __func__, ret); - - if (event == WDSP_EVENT_POST_DLOAD_CODE) - /* Mark DSP online since code download is complete */ - wcd_cntl_change_online_state(cntl, 1); - break; case WDSP_EVENT_PRE_DLOAD_DATA: diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c index b96b0d6effe7b308b8e9d07839e0e07c17a4143a..075ab7b2ff2b5a0d563df99409e4407faa572efe 100644 --- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c +++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c @@ -42,7 +42,7 @@ /* Z floating defined in ohms */ #define TAVIL_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE -#define TAVIL_ZDET_NUM_MEASUREMENTS 900 +#define TAVIL_ZDET_NUM_MEASUREMENTS 150 #define TAVIL_MBHC_GET_C1(c) ((c & 0xC000) >> 14) #define TAVIL_MBHC_GET_X1(x) (x & 0x3FFF) /* Z value compared in milliOhm */ diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c index 9218786f913ffb007660f4255ba121b250f72672..7b79214f99b0d397c9a9ac7232906387a695ae0e 100644 --- a/sound/soc/codecs/wcd_cpe_core.c +++ b/sound/soc/codecs/wcd_cpe_core.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -822,6 +827,8 @@ static int wcd_cpe_enable(struct wcd_cpe_core *core, bool enable) { int ret = 0; + int timeout = 0; + int err_cnt = 0; if (enable) { /* Reset CPE first */ @@ -844,8 +851,19 @@ static int wcd_cpe_enable(struct wcd_cpe_core *core, if (ret) goto fail_boot; - /* Dload data section */ - ret = wcd_cpe_load_fw(core, ELF_FLAG_RW); + for (err_cnt = 0; err_cnt < 10; err_cnt++) { + /* Dload data section */ + ret = wcd_cpe_load_fw(core, ELF_FLAG_RW); + if (ret) { + pr_err("%s: wcd_cpe_load_fw error ret=%d. retry.\n", __func__, ret); + msleep(5); + } else { + if (err_cnt > 0) { + pr_err("%s: wcd_cpe_load_fw error count=%d.\n", __func__, err_cnt); + } + break; + } + } if (ret) { dev_err(core->dev, "%s: Failed to dload data section, err = %d\n", @@ -874,9 +892,18 @@ static int wcd_cpe_enable(struct wcd_cpe_core *core, dev_dbg(core->dev, "%s: waiting for CPE bootup\n", __func__); - +#if 0 wait_for_completion(&core->online_compl); - +#else + timeout = wait_for_completion_timeout(&core->online_compl, msecs_to_jiffies(1000)); + if (!timeout) { + dev_err(core->dev, + "%s: Timeout boot CPE.\n", + __func__); + ret = -ETIMEDOUT; + goto fail_boot; + } +#endif dev_dbg(core->dev, "%s: CPE bootup done\n", __func__); @@ -1189,6 +1216,9 @@ static irqreturn_t svass_exception_irq(int irq, void *data) dev_err(core->dev, "%s: CPE SSR event,err_status = 0x%02x\n", __func__, status); + core->ssr_entry.err_status = status; + core->ssr_entry.err_data_ready = 1; + wake_up(&core->ssr_entry.err_status_debug_q); wcd_cpe_ssr_event(core, WCD_CPE_SSR_EVENT); /* * If fatal interrupt is received, @@ -1673,6 +1703,44 @@ done: return ret; } +static ssize_t cpe_err_status_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + int r; + char buf[32]; + size_t size; + struct wcd_cpe_core *core = filp->private_data; + struct wcd_cpe_ssr_entry *ssr_entry = &core->ssr_entry; + + r = snprintf(buf, sizeof(buf), + "err_status = 0x%02x", ssr_entry->err_status); + size = simple_read_from_buffer(ubuf, cnt, ppos, buf, r); + if (*ppos == r) + ssr_entry->err_data_ready = 0; + + return size; +} + +static unsigned int cpe_err_status_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct wcd_cpe_core *core = filp->private_data; + struct wcd_cpe_ssr_entry *ssr_entry = &core->ssr_entry; + unsigned int mask = 0; + + if (ssr_entry->err_data_ready) + mask |= (POLLIN | POLLRDNORM); + + poll_wait(filp, &ssr_entry->err_status_debug_q, wait); + return mask; +} + +static const struct file_operations cpe_err_status_fops = { + .open = simple_open, + .read = cpe_err_status_read, + .poll = cpe_err_status_poll, +}; + static int wcd_cpe_debugfs_init(struct wcd_cpe_core *core) { int rc = 0; @@ -1708,6 +1776,18 @@ static int wcd_cpe_debugfs_init(struct wcd_cpe_core *core) goto err_create_entry; } + if (!debugfs_create_file("err_status", S_IRUGO, + dir, core, &cpe_err_status_fops)) { + dev_err(core->dev, "%s: Failed to create debugfs node %s\n", + __func__, "err_status"); + rc = -ENODEV; + goto err_create_entry; + } + + init_waitqueue_head(&core->ssr_entry.err_status_debug_q); + + return 0; + err_create_entry: debugfs_remove(dir); diff --git a/sound/soc/codecs/wcd_cpe_core.h b/sound/soc/codecs/wcd_cpe_core.h index b09b03d2f81d80e8e36f27d925057c43edd47993..63eca6a10926d026ded8f5af7f2d61a1bd8badf4 100644 --- a/sound/soc/codecs/wcd_cpe_core.h +++ b/sound/soc/codecs/wcd_cpe_core.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef WCD_CPE_CORE_H #define WCD_CPE_CORE_H @@ -95,6 +100,9 @@ struct wcd_cpe_ssr_entry { int offline; u32 offline_change; wait_queue_head_t offline_poll_wait; + int err_status; + int err_data_ready; + wait_queue_head_t err_status_debug_q; struct snd_info_entry *entry; }; diff --git a/sound/soc/codecs/wcd_cpe_services.c b/sound/soc/codecs/wcd_cpe_services.c index 582fddfa1096cd2adf8aaa4fca00b682b22343c6..2c8704c884d2c1099485a338a349131ac72dc229 100644 --- a/sound/soc/codecs/wcd_cpe_services.c +++ b/sound/soc/codecs/wcd_cpe_services.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -2863,8 +2868,19 @@ static enum cpe_svc_result cpe_tgt_wcd9335_write_RAM(struct cpe_info *t_info, return CPE_SVC_FAILED; } +#if 0 cpe_register_write_repeat(WCD9335_CPE_SS_MEM_BANK_0, temp_ptr, to_write); +#else + rc = cpe_register_write_repeat(WCD9335_CPE_SS_MEM_BANK_0, + temp_ptr, to_write); + if (rc) { + pr_err("%s: cpe_register_write_repeat error rc=%d\n", __func__, rc); + cpe_register_write(WCD9335_CPE_SS_MEM_CTRL, 0); + return rc; + } +#endif + temp_size += CHUNK_SIZE; temp_ptr += CHUNK_SIZE; } diff --git a/sound/soc/codecs/wcdcal-hwdep.c b/sound/soc/codecs/wcdcal-hwdep.c old mode 100755 new mode 100644 index 58e51542ed66d43b5398bb3157e4e8234882c48e..ea81bd401c7abda2f3973e8257bca38f61971f08 --- a/sound/soc/codecs/wcdcal-hwdep.c +++ b/sound/soc/codecs/wcdcal-hwdep.c @@ -11,6 +11,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -22,7 +27,7 @@ #include "wcdcal-hwdep.h" const int cal_size_info[WCD9XXX_MAX_CAL] = { - [WCD9XXX_ANC_CAL] = 16384, + [WCD9XXX_ANC_CAL] = 36864, [WCD9XXX_MBHC_CAL] = 4096, [WCD9XXX_MAD_CAL] = 4096, [WCD9XXX_VBAT_CAL] = 72, diff --git a/sound/soc/codecs/wsa881x-regmap.c b/sound/soc/codecs/wsa881x-regmap.c index 20dc3508a5aff30e47139e35f9dd9595a85acdd0..909f63d53029bb520de4324fe458dd0ed93ce8eb 100644 --- a/sound/soc/codecs/wsa881x-regmap.c +++ b/sound/soc/codecs/wsa881x-regmap.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -174,7 +179,7 @@ static struct reg_sequence wsa881x_rev_2_0[] = { {WSA881X_SPKR_BIAS_INT, 0x5F, 0x00}, {WSA881X_SPKR_BIAS_PSRR, 0x44, 0x00}, {WSA881X_BOOST_PS_CTL, 0xA0, 0x00}, - {WSA881X_BOOST_PRESET_OUT1, 0xB7, 0x00}, + {WSA881X_BOOST_PRESET_OUT1, 0x37, 0x00}, {WSA881X_BOOST_LOOP_STABILITY, 0x8D, 0x00}, {WSA881X_SPKR_PROT_ATEST2, 0x02, 0x00}, {WSA881X_BONGO_RESRV_REG1, 0x5E, 0x00}, diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index e4f6df077d98f2095289488397d8499630ee3a02..f3114542cec09b1ad4e4ea5ea7586171b092f3cd 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2017 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -74,6 +79,7 @@ struct swr_port { }; enum { + WSA881X_DEV_RESET, WSA881X_DEV_DOWN, WSA881X_DEV_UP, }; @@ -968,8 +974,6 @@ static void wsa881x_init(struct snd_soc_codec *codec) wsa881x->version = snd_soc_read(codec, WSA881X_CHIP_ID1); wsa881x_regmap_defaults(wsa881x->regmap, wsa881x->version); - /* Enable software reset output from soundwire slave */ - snd_soc_update_bits(codec, WSA881X_SWR_RESET_EN, 0x07, 0x07); /* Bring out of analog reset */ snd_soc_update_bits(codec, WSA881X_CDC_RST_CTL, 0x02, 0x02); /* Bring out of digital reset */ @@ -993,7 +997,7 @@ static void wsa881x_init(struct snd_soc_codec *codec) 0x03, 0x00); if (snd_soc_read(codec, WSA881X_OTP_REG_0)) snd_soc_update_bits(codec, WSA881X_BOOST_PRESET_OUT1, - 0xF0, 0x70); + 0xFF, 0x7F); snd_soc_update_bits(codec, WSA881X_BOOST_PRESET_OUT2, 0xF0, 0x30); snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x08, 0x08); @@ -1361,6 +1365,10 @@ static int wsa881x_swr_reset(struct swr_device *pdev) dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__); return -EINVAL; } + if (wsa881x->state == WSA881X_DEV_RESET) { + dev_err(&pdev->dev, "Device is already reset"); + return 0; + } wsa881x->bg_cnt = 0; wsa881x->clk_cnt = 0; while (swr_get_logical_dev_num(pdev, pdev->addr, &devnum) && retry--) { @@ -1370,6 +1378,7 @@ static int wsa881x_swr_reset(struct swr_device *pdev) pdev->dev_num = devnum; regcache_mark_dirty(wsa881x->regmap); regcache_sync(wsa881x->regmap); + wsa881x->state = WSA881X_DEV_RESET; return 0; } diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig index eb650d19a97c0a086f67e111a05b5ddc285dd953..04501f056bf94070b8c8b98904d2d3fabcabb8da 100644 --- a/sound/soc/msm/Kconfig +++ b/sound/soc/msm/Kconfig @@ -30,6 +30,24 @@ config SND_SOC_QDSP_DEBUG is inducing kernel panic upon encountering critical errors from DSP audio modules +config AHC + bool "Enable Automatic Headset Compensation" + depends on SND_SOC_MSM_QDSP6V2_INTF + help + To add support for Automatic Headset Compensation post processing. + This support is to configure the post processing parameters + to DSP. The configuration includes enabling and setting up + the IIR tuning filter and MBDRC in the DSP. + +config FORCE_24BIT_COPP + bool "Configure COPP in ADSP as 24-bit" + depends on SND_SOC_MSM_QDSP6V2_INTF + default n + help + To configure COPP in ADSP as 24bit for media playback. + This can avoid quantization error for 16-bit media playback + when IIR/MBDRC filters are enabled. + config DOLBY_DS2 bool "Enable Dolby DS2" depends on SND_SOC_MSM_QDSP6V2_INTF diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c index 749f386852c69bfc19418da655cc2c94111bada2..b6121d75c148b438e4e9d84c9b746861a577cd06 100644 --- a/sound/soc/msm/apq8096-auto.c +++ b/sound/soc/msm/apq8096-auto.c @@ -61,16 +61,6 @@ static int msm_quat_mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_sec_mi2s_rate = SAMPLING_RATE_48KHZ; /* TDM default channels */ -static int msm_pri_tdm_tx_0_ch = 2; -static int msm_pri_tdm_tx_1_ch = 2; -static int msm_pri_tdm_tx_2_ch = 2; -static int msm_pri_tdm_tx_3_ch = 2; - -static int msm_pri_tdm_rx_0_ch = 2; -static int msm_pri_tdm_rx_1_ch = 2; -static int msm_pri_tdm_rx_2_ch = 2; -static int msm_pri_tdm_rx_3_ch = 2; - static int msm_sec_tdm_tx_0_ch = 2; /* STEREO MIC */ static int msm_sec_tdm_tx_1_ch = 2; static int msm_sec_tdm_tx_2_ch = 2; @@ -98,16 +88,6 @@ static int msm_quat_tdm_tx_2_ch = 2; /*ENT RECORD*/ static int msm_quat_tdm_tx_3_ch; /* TDM default bit format */ -static int msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; -static int msm_pri_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; -static int msm_pri_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; -static int msm_pri_tdm_tx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; - -static int msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; -static int msm_pri_tdm_rx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; -static int msm_pri_tdm_rx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; -static int msm_pri_tdm_rx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; - static int msm_sec_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_sec_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_sec_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; @@ -134,10 +114,6 @@ static int msm_quat_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_quat_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_quat_tdm_tx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; -static int msm_pri_tdm_rate = SAMPLING_RATE_48KHZ; -static int msm_pri_tdm_slot_width = 32; -static int msm_pri_tdm_slot_num = 8; - /* EC Reference default values are set in mixer_paths.xml */ static int msm_ec_ref_ch = 4; static int msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S16_LE; @@ -198,26 +174,11 @@ enum { SECONDARY_TDM_TX_5, SECONDARY_TDM_TX_6, SECONDARY_TDM_TX_7, - PRIMARY_TDM_RX_0, - PRIMARY_TDM_RX_1, - PRIMARY_TDM_RX_2, - PRIMARY_TDM_RX_3, - PRIMARY_TDM_RX_4, - PRIMARY_TDM_RX_5, - PRIMARY_TDM_RX_6, - PRIMARY_TDM_RX_7, - PRIMARY_TDM_TX_0, - PRIMARY_TDM_TX_1, - PRIMARY_TDM_TX_2, - PRIMARY_TDM_TX_3, - PRIMARY_TDM_TX_4, - PRIMARY_TDM_TX_5, - PRIMARY_TDM_TX_6, - PRIMARY_TDM_TX_7, TDM_MAX, }; #define TDM_SLOT_OFFSET_MAX 8 + /* TDM default offset */ static unsigned int tdm_slot_offset[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { /* QUAT_TDM_RX */ @@ -274,24 +235,6 @@ static unsigned int tdm_slot_offset[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - /* PRI_TDM_RX */ - {0, 4, 0xFFFF}, - {8, 12, 0xFFFF}, - {16, 20, 0xFFFF}, - {24, 28, 0xFFFF}, - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - /* PRI_TDM_TX */ - {0, 4, 0xFFFF}, - {8, 12, 0xFFFF}, - {16, 20, 0xFFFF}, - {24, 28, 0xFFFF}, - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ }; @@ -357,24 +300,6 @@ static unsigned int tdm_slot_offset_adp_mmxf[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - /* PRI_TDM_RX */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - /* PRI_TDM_TX */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ }; static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { @@ -432,24 +357,6 @@ static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - /* PRI_TDM_RX */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - /* PRI_TDM_TX */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ }; static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", @@ -482,14 +389,6 @@ static const char *const ec_ref_rate_text[] = {"0", "8000", "16000", static const char *const mi2s_rate_text[] = {"32000", "44100", "48000"}; -static const char *const pri_tdm_rate_text[] = {"8000", "16000", "48000"}; - -static const char *const pri_tdm_slot_num_text[] = {"One", "Two", "Four", - "Eight", "Sixteen", "Thirtytwo"}; - - -static const char *const pri_tdm_slot_width_text[] = {"16", "24", "32"}; - static struct afe_clk_set sec_mi2s_tx_clk = { AFE_API_VERSION_I2S_CONFIG, Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT, @@ -799,150 +698,6 @@ static int msm_sec_mi2s_tx_bit_format_put(struct snd_kcontrol *kcontrol, return 0; } -static int msm_pri_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_pri_tdm_tx_0_ch = %d\n", __func__, - msm_pri_tdm_tx_0_ch); - ucontrol->value.integer.value[0] = msm_pri_tdm_tx_0_ch - 1; - return 0; -} - -static int msm_pri_tdm_tx_0_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_pri_tdm_tx_0_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_pri_tdm_tx_0_ch = %d\n", __func__, - msm_pri_tdm_tx_0_ch); - return 0; -} - -static int msm_pri_tdm_tx_1_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: pri_tdm_tx_1_ch = %d\n", __func__, - msm_pri_tdm_tx_1_ch); - ucontrol->value.integer.value[0] = msm_pri_tdm_tx_1_ch - 1; - return 0; -} - -static int msm_pri_tdm_tx_1_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_pri_tdm_tx_1_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_pri_tdm_tx_1_ch = %d\n", __func__, - msm_pri_tdm_tx_1_ch); - return 0; -} - -static int msm_pri_tdm_tx_2_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_pri_tdm_tx_2_ch = %d\n", __func__, - msm_pri_tdm_tx_2_ch); - ucontrol->value.integer.value[0] = msm_pri_tdm_tx_2_ch - 1; - return 0; -} - -static int msm_pri_tdm_tx_2_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_pri_tdm_tx_2_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_pri_tdm_tx_2_ch = %d\n", __func__, - msm_pri_tdm_tx_2_ch); - return 0; -} - -static int msm_pri_tdm_tx_3_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_pri_tdm_tx_3_ch = %d\n", __func__, - msm_pri_tdm_tx_3_ch); - ucontrol->value.integer.value[0] = msm_pri_tdm_tx_3_ch - 1; - return 0; -} - -static int msm_pri_tdm_tx_3_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_pri_tdm_tx_3_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_pri_tdm_tx_3_ch = %d\n", __func__, - msm_pri_tdm_tx_3_ch); - return 0; -} - -static int msm_pri_tdm_rx_0_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_pri_tdm_rx_0_ch = %d\n", __func__, - msm_pri_tdm_rx_0_ch); - ucontrol->value.integer.value[0] = msm_pri_tdm_rx_0_ch - 1; - return 0; -} - -static int msm_pri_tdm_rx_0_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_pri_tdm_rx_0_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_pri_tdm_rx_0_ch = %d\n", __func__, - msm_pri_tdm_rx_0_ch); - return 0; -} - -static int msm_pri_tdm_rx_1_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_pri_tdm_rx_1_ch = %d\n", __func__, - msm_pri_tdm_rx_1_ch); - ucontrol->value.integer.value[0] = msm_pri_tdm_rx_1_ch - 1; - return 0; -} - -static int msm_pri_tdm_rx_1_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_pri_tdm_rx_1_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_pri_tdm_rx_1_ch = %d\n", __func__, - msm_pri_tdm_rx_1_ch); - return 0; -} - -static int msm_pri_tdm_rx_2_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_pri_tdm_rx_2_ch = %d\n", __func__, - msm_pri_tdm_rx_2_ch); - ucontrol->value.integer.value[0] = msm_pri_tdm_rx_2_ch - 1; - return 0; -} - -static int msm_pri_tdm_rx_2_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_pri_tdm_rx_2_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_pri_tdm_rx_2_ch = %d\n", __func__, - msm_pri_tdm_rx_2_ch); - return 0; -} - -static int msm_pri_tdm_rx_3_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_pri_tdm_rx_3_ch = %d\n", __func__, - msm_pri_tdm_rx_3_ch); - ucontrol->value.integer.value[0] = msm_pri_tdm_rx_3_ch - 1; - return 0; -} - -static int msm_pri_tdm_rx_3_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_pri_tdm_rx_3_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_pri_tdm_rx_3_ch = %d\n", __func__, - msm_pri_tdm_rx_3_ch); - return 0; -} - static int msm_sec_mi2s_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -973,174 +728,6 @@ static int msm_sec_mi2s_rate_put(struct snd_kcontrol *kcontrol, return 0; } -static int msm_pri_tdm_rate_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = msm_pri_tdm_rate; - pr_debug("%s: msm_pri_tdm_rate = %d\n", __func__, msm_pri_tdm_rate); - return 0; -} - -static int msm_pri_tdm_rate_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - switch (ucontrol->value.integer.value[0]) { - case 0: - msm_pri_tdm_rate = SAMPLING_RATE_8KHZ; - break; - case 1: - msm_pri_tdm_rate = SAMPLING_RATE_16KHZ; - break; - case 2: - msm_pri_tdm_rate = SAMPLING_RATE_48KHZ; - break; - default: - msm_pri_tdm_rate = SAMPLING_RATE_48KHZ; - break; - } - pr_debug("%s: msm_pri_tdm_rate = %d\n", - __func__, msm_pri_tdm_rate); - return 0; -} - -static int msm_pri_tdm_slot_width_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = msm_pri_tdm_slot_width; - pr_debug("%s: msm_pri_tdm_slot_width = %d\n", - __func__, msm_pri_tdm_slot_width); - return 0; -} - -static int msm_pri_tdm_slot_width_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - switch (ucontrol->value.integer.value[0]) { - case 0: - msm_pri_tdm_slot_width = 16; - break; - case 1: - msm_pri_tdm_slot_width = 24; - break; - case 2: - msm_pri_tdm_slot_width = 32; - break; - default: - msm_pri_tdm_slot_width = 32; - break; - } - pr_debug("%s: msm_pri_tdm_slot_width= %d\n", - __func__, msm_pri_tdm_slot_width); - return 0; -} - -static int msm_pri_tdm_slot_num_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - switch (msm_pri_tdm_slot_num) { - case 1: - ucontrol->value.integer.value[0] = 0; - break; - case 2: - ucontrol->value.integer.value[0] = 1; - break; - case 4: - ucontrol->value.integer.value[0] = 2; - break; - case 8: - ucontrol->value.integer.value[0] = 3; - break; - case 16: - ucontrol->value.integer.value[0] = 4; - break; - case 32: - default: - ucontrol->value.integer.value[0] = 5; - break; - } - - pr_debug("%s: msm_pri_tdm_slot_num = %d\n", - __func__, msm_pri_tdm_slot_num); - return 0; -} - -static int msm_pri_tdm_slot_num_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - switch (ucontrol->value.integer.value[0]) { - case 0: - msm_pri_tdm_slot_num = 1; - break; - case 1: - msm_pri_tdm_slot_num = 2; - break; - case 2: - msm_pri_tdm_slot_num = 4; - break; - case 3: - msm_pri_tdm_slot_num = 8; - break; - case 4: - msm_pri_tdm_slot_num = 16; - break; - case 5: - msm_pri_tdm_slot_num = 32; - break; - default: - msm_pri_tdm_slot_num = 8; - break; - } - pr_debug("%s: msm_pri_tdm_slot_num = %d\n", - __func__, msm_pri_tdm_slot_num); - return 0; -} - -static int msm_tdm_slot_mapping_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_multi_mixer_control *mc = - (struct soc_multi_mixer_control *)kcontrol->private_value; - unsigned int *slot_offset; - int i; - - if (mc->shift >= TDM_MAX) { - pr_err("%s invalid port index %d\n", __func__, mc->shift); - return -EINVAL; - } - - slot_offset = tdm_slot_offset[mc->shift]; - for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) { - ucontrol->value.integer.value[i] = slot_offset[i]; - pr_debug("%s port index %d offset %d value %d\n", - __func__, mc->shift, i, slot_offset[i]); - } - - return 0; -} - -static int msm_tdm_slot_mapping_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_multi_mixer_control *mc = - (struct soc_multi_mixer_control *)kcontrol->private_value; - unsigned int *slot_offset; - int i; - - if (mc->shift >= TDM_MAX) { - pr_err("%s invalid port index %d\n", __func__, mc->shift); - return -EINVAL; - } - - slot_offset = tdm_slot_offset[mc->shift]; - - for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) { - slot_offset[i] = ucontrol->value.integer.value[i]; - pr_debug("%s port index %d offset %d value %d\n", - __func__, mc->shift, i, slot_offset[i]); - } - - return 0; -} static int msm_sec_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1404,391 +991,119 @@ static int msm_quat_tdm_rx_1_ch_get(struct snd_kcontrol *kcontrol, } static int msm_quat_tdm_rx_1_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_quat_tdm_rx_1_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_quat_tdm_rx_1_ch = %d\n", __func__, - msm_quat_tdm_rx_1_ch); - return 0; -} - -static int msm_quat_tdm_rx_2_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_quat_tdm_rx_2_ch = %d\n", __func__, - msm_quat_tdm_rx_2_ch); - ucontrol->value.integer.value[0] = msm_quat_tdm_rx_2_ch - 1; - return 0; -} - -static int msm_quat_tdm_rx_2_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_quat_tdm_rx_2_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_quat_tdm_rx_2_ch = %d\n", __func__, - msm_quat_tdm_rx_2_ch); - return 0; -} - -static int msm_quat_tdm_rx_3_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_quat_tdm_rx_3_ch = %d\n", __func__, - msm_quat_tdm_rx_3_ch); - ucontrol->value.integer.value[0] = msm_quat_tdm_rx_3_ch - 1; - return 0; -} - -static int msm_quat_tdm_rx_3_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_quat_tdm_rx_3_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_quat_tdm_rx_3_ch = %d\n", __func__, - msm_quat_tdm_rx_3_ch); - return 0; -} - -static int msm_quat_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_quat_tdm_tx_0_ch = %d\n", __func__, - msm_quat_tdm_tx_0_ch); - ucontrol->value.integer.value[0] = msm_quat_tdm_tx_0_ch - 1; - return 0; -} - -static int msm_quat_tdm_tx_0_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_quat_tdm_tx_0_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_quat_tdm_tx_0_ch = %d\n", __func__, - msm_quat_tdm_tx_0_ch); - return 0; -} - -static int msm_quat_tdm_tx_1_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_quat_tdm_tx_1_ch = %d\n", __func__, - msm_quat_tdm_tx_1_ch); - ucontrol->value.integer.value[0] = msm_quat_tdm_tx_1_ch - 1; - return 0; -} - -static int msm_quat_tdm_tx_1_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_quat_tdm_tx_1_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_quat_tdm_tx_1_ch = %d\n", __func__, - msm_quat_tdm_tx_1_ch); - return 0; -} - -static int msm_quat_tdm_tx_2_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_quat_tdm_tx_2_ch = %d\n", __func__, - msm_quat_tdm_tx_2_ch); - ucontrol->value.integer.value[0] = msm_quat_tdm_tx_2_ch - 1; - return 0; -} - -static int msm_quat_tdm_tx_2_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_quat_tdm_tx_2_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_quat_tdm_tx_2_ch = %d\n", __func__, - msm_quat_tdm_tx_2_ch); - return 0; -} - -static int msm_quat_tdm_tx_3_ch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - pr_debug("%s: msm_quat_tdm_tx_3_ch = %d\n", __func__, - msm_quat_tdm_tx_3_ch); - ucontrol->value.integer.value[0] = msm_quat_tdm_tx_3_ch - 1; - return 0; -} - -static int msm_quat_tdm_tx_3_ch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - msm_quat_tdm_tx_3_ch = ucontrol->value.integer.value[0] + 1; - pr_debug("%s: msm_quat_tdm_tx_3_ch = %d\n", __func__, - msm_quat_tdm_tx_3_ch); - return 0; -} - -static int msm_pri_tdm_tx_0_bit_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - switch (msm_pri_tdm_tx_0_bit_format) { - case SNDRV_PCM_FORMAT_S24_LE: - ucontrol->value.integer.value[0] = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - default: - ucontrol->value.integer.value[0] = 0; - break; - } - pr_debug("%s: msm_pri_tdm_tx_0_bit_format = %ld\n", - __func__, ucontrol->value.integer.value[0]); - return 0; -} - -static int msm_pri_tdm_tx_0_bit_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - switch (ucontrol->value.integer.value[0]) { - case 1: - msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; - break; - case 0: - default: - msm_pri_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; - break; - } - pr_debug("%s: msm_pri_tdm_tx_0_bit_format = %d\n", - __func__, msm_pri_tdm_tx_0_bit_format); - return 0; -} - -static int msm_pri_tdm_tx_1_bit_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - switch (msm_pri_tdm_tx_1_bit_format) { - case SNDRV_PCM_FORMAT_S24_LE: - ucontrol->value.integer.value[0] = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - default: - ucontrol->value.integer.value[0] = 0; - break; - } - pr_debug("%s: msm_pri_tdm_tx_1_bit_format = %ld\n", - __func__, ucontrol->value.integer.value[0]); - return 0; -} - -static int msm_pri_tdm_tx_1_bit_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { - switch (ucontrol->value.integer.value[0]) { - case 1: - msm_pri_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S24_LE; - break; - case 0: - default: - msm_pri_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; - break; - } - pr_debug("%s: msm_pri_tdm_tx_1_bit_format = %d\n", - __func__, msm_pri_tdm_tx_1_bit_format); + msm_quat_tdm_rx_1_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_quat_tdm_rx_1_ch = %d\n", __func__, + msm_quat_tdm_rx_1_ch); return 0; } -static int msm_pri_tdm_tx_2_bit_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_rx_2_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (msm_pri_tdm_tx_2_bit_format) { - case SNDRV_PCM_FORMAT_S24_LE: - ucontrol->value.integer.value[0] = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - default: - ucontrol->value.integer.value[0] = 0; - break; - } - pr_debug("%s: msm_pri_tdm_tx_2_bit_format = %ld\n", - __func__, ucontrol->value.integer.value[0]); + pr_debug("%s: msm_quat_tdm_rx_2_ch = %d\n", __func__, + msm_quat_tdm_rx_2_ch); + ucontrol->value.integer.value[0] = msm_quat_tdm_rx_2_ch - 1; return 0; } -static int msm_pri_tdm_tx_2_bit_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_rx_2_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (ucontrol->value.integer.value[0]) { - case 1: - msm_pri_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S24_LE; - break; - case 0: - default: - msm_pri_tdm_tx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; - break; - } - pr_debug("%s: msm_pri_tdm_tx_2_bit_format = %d\n", - __func__, msm_pri_tdm_tx_2_bit_format); + msm_quat_tdm_rx_2_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_quat_tdm_rx_2_ch = %d\n", __func__, + msm_quat_tdm_rx_2_ch); return 0; } -static int msm_pri_tdm_tx_3_bit_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_rx_3_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (msm_pri_tdm_tx_3_bit_format) { - case SNDRV_PCM_FORMAT_S24_LE: - ucontrol->value.integer.value[0] = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - default: - ucontrol->value.integer.value[0] = 0; - break; - } - pr_debug("%s: msm_pri_tdm_tx_3_bit_format = %ld\n", - __func__, ucontrol->value.integer.value[0]); + pr_debug("%s: msm_quat_tdm_rx_3_ch = %d\n", __func__, + msm_quat_tdm_rx_3_ch); + ucontrol->value.integer.value[0] = msm_quat_tdm_rx_3_ch - 1; return 0; } -static int msm_pri_tdm_tx_3_bit_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_rx_3_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (ucontrol->value.integer.value[0]) { - case 1: - msm_pri_tdm_tx_3_bit_format = SNDRV_PCM_FORMAT_S24_LE; - break; - case 0: - default: - msm_pri_tdm_tx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; - break; - } - pr_debug("%s: msm_pri_tdm_tx_3_bit_format = %d\n", - __func__, msm_pri_tdm_tx_3_bit_format); + msm_quat_tdm_rx_3_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_quat_tdm_rx_3_ch = %d\n", __func__, + msm_quat_tdm_rx_3_ch); return 0; } -static int msm_pri_tdm_rx_0_bit_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (msm_pri_tdm_rx_0_bit_format) { - case SNDRV_PCM_FORMAT_S24_LE: - ucontrol->value.integer.value[0] = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - default: - ucontrol->value.integer.value[0] = 0; - break; - } - pr_debug("%s: msm_pri_tdm_rx_0_bit_format = %ld\n", - __func__, ucontrol->value.integer.value[0]); + pr_debug("%s: msm_quat_tdm_tx_0_ch = %d\n", __func__, + msm_quat_tdm_tx_0_ch); + ucontrol->value.integer.value[0] = msm_quat_tdm_tx_0_ch - 1; return 0; } -static int msm_pri_tdm_rx_0_bit_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_tx_0_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (ucontrol->value.integer.value[0]) { - case 1: - msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S24_LE; - break; - case 0: - default: - msm_pri_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE; - break; - } - pr_debug("%s: msm_pri_tdm_rx_0_bit_format = %d\n", - __func__, msm_pri_tdm_rx_0_bit_format); + msm_quat_tdm_tx_0_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_quat_tdm_tx_0_ch = %d\n", __func__, + msm_quat_tdm_tx_0_ch); return 0; } -static int msm_pri_tdm_rx_1_bit_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_tx_1_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (msm_pri_tdm_rx_1_bit_format) { - case SNDRV_PCM_FORMAT_S24_LE: - ucontrol->value.integer.value[0] = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - default: - ucontrol->value.integer.value[0] = 0; - break; - } - pr_debug("%s: msm_pri_tdm_rx_1_bit_format = %ld\n", - __func__, ucontrol->value.integer.value[0]); + pr_debug("%s: msm_quat_tdm_tx_1_ch = %d\n", __func__, + msm_quat_tdm_tx_1_ch); + ucontrol->value.integer.value[0] = msm_quat_tdm_tx_1_ch - 1; return 0; } -static int msm_pri_tdm_rx_1_bit_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_tx_1_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (ucontrol->value.integer.value[0]) { - case 1: - msm_pri_tdm_rx_1_bit_format = SNDRV_PCM_FORMAT_S24_LE; - break; - case 0: - default: - msm_pri_tdm_rx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE; - break; - } - pr_debug("%s: msm_pri_tdm_rx_1_bit_format = %d\n", - __func__, msm_pri_tdm_rx_1_bit_format); + msm_quat_tdm_tx_1_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_quat_tdm_tx_1_ch = %d\n", __func__, + msm_quat_tdm_tx_1_ch); return 0; } -static int msm_pri_tdm_rx_2_bit_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_tx_2_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (msm_pri_tdm_rx_2_bit_format) { - case SNDRV_PCM_FORMAT_S24_LE: - ucontrol->value.integer.value[0] = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - default: - ucontrol->value.integer.value[0] = 0; - break; - } - pr_debug("%s: msm_pri_tdm_rx_2_bit_format = %ld\n", - __func__, ucontrol->value.integer.value[0]); + pr_debug("%s: msm_quat_tdm_tx_2_ch = %d\n", __func__, + msm_quat_tdm_tx_2_ch); + ucontrol->value.integer.value[0] = msm_quat_tdm_tx_2_ch - 1; return 0; } -static int msm_pri_tdm_rx_2_bit_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_tx_2_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (ucontrol->value.integer.value[0]) { - case 1: - msm_pri_tdm_rx_2_bit_format = SNDRV_PCM_FORMAT_S24_LE; - break; - case 0: - default: - msm_pri_tdm_rx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE; - break; - } - pr_debug("%s: msm_pri_tdm_rx_2_bit_format = %d\n", - __func__, msm_pri_tdm_rx_2_bit_format); + msm_quat_tdm_tx_2_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_quat_tdm_tx_2_ch = %d\n", __func__, + msm_quat_tdm_tx_2_ch); return 0; } -static int msm_pri_tdm_rx_3_bit_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_tx_3_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (msm_pri_tdm_rx_3_bit_format) { - case SNDRV_PCM_FORMAT_S24_LE: - ucontrol->value.integer.value[0] = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - default: - ucontrol->value.integer.value[0] = 0; - break; - } - pr_debug("%s: msm_pri_tdm_rx_3_bit_format = %ld\n", - __func__, ucontrol->value.integer.value[0]); + pr_debug("%s: msm_quat_tdm_tx_3_ch = %d\n", __func__, + msm_quat_tdm_tx_3_ch); + ucontrol->value.integer.value[0] = msm_quat_tdm_tx_3_ch - 1; return 0; } -static int msm_pri_tdm_rx_3_bit_format_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_quat_tdm_tx_3_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - switch (ucontrol->value.integer.value[0]) { - case 1: - msm_pri_tdm_rx_3_bit_format = SNDRV_PCM_FORMAT_S24_LE; - break; - case 0: - default: - msm_pri_tdm_rx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE; - break; - } - pr_debug("%s: msm_pri_tdm_rx_3_bit_format = %d\n", - __func__, msm_pri_tdm_rx_3_bit_format); + msm_quat_tdm_tx_3_ch = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: msm_quat_tdm_tx_3_ch = %d\n", __func__, + msm_quat_tdm_tx_3_ch); return 0; } @@ -2755,57 +2070,7 @@ static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - rate->min = rate->max = SAMPLING_RATE_48KHZ; - switch (cpu_dai->id) { - case AFE_PORT_ID_PRIMARY_TDM_TX: - channels->min = channels->max = msm_pri_tdm_tx_0_ch; - param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - msm_pri_tdm_tx_0_bit_format); - rate->min = rate->max = msm_pri_tdm_rate; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_1: - channels->min = channels->max = msm_pri_tdm_tx_1_ch; - param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - msm_pri_tdm_tx_1_bit_format); - rate->min = rate->max = msm_pri_tdm_rate; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_2: - channels->min = channels->max = msm_pri_tdm_tx_2_ch; - param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - msm_pri_tdm_tx_2_bit_format); - rate->min = rate->max = msm_pri_tdm_rate; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_3: - channels->min = channels->max = msm_pri_tdm_tx_3_ch; - param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - msm_pri_tdm_tx_3_bit_format); - rate->min = rate->max = msm_pri_tdm_rate; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX: - channels->min = channels->max = msm_pri_tdm_rx_0_ch; - param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - msm_pri_tdm_rx_0_bit_format); - rate->min = rate->max = msm_pri_tdm_rate; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_1: - channels->min = channels->max = msm_pri_tdm_rx_1_ch; - param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - msm_pri_tdm_rx_1_bit_format); - rate->min = rate->max = msm_pri_tdm_rate; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_2: - channels->min = channels->max = msm_pri_tdm_rx_2_ch; - param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - msm_pri_tdm_rx_2_bit_format); - rate->min = rate->max = msm_pri_tdm_rate; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_3: - channels->min = channels->max = msm_pri_tdm_rx_3_ch; - param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, - msm_pri_tdm_rx_3_bit_format); - rate->min = rate->max = msm_pri_tdm_rate; - break; case AFE_PORT_ID_SECONDARY_TDM_TX: channels->min = channels->max = msm_sec_tdm_tx_0_ch; param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, @@ -2916,6 +2181,7 @@ static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, __func__, cpu_dai->id); return -EINVAL; } + rate->min = rate->max = SAMPLING_RATE_48KHZ; pr_debug("%s: dai id = 0x%x channels = %d rate = %d format = 0x%x\n", __func__, cpu_dai->id, channels->max, rate->max, @@ -3007,45 +2273,126 @@ static void apq8096_mi2s_snd_shutdown(struct snd_pcm_substream *substream) pr_err("%s: afe lpass clock failed, err:%d\n", __func__, ret); break; - case 2: /*MSM_TERT_MI2S*/ - mi2s_tx_clk.enable = 0; - ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX, - &mi2s_tx_clk); - if (ret < 0) - pr_err("%s: afe lpass clock failed, err:%d\n", - __func__, ret); + case 2: /*MSM_TERT_MI2S*/ + mi2s_tx_clk.enable = 0; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX, + &mi2s_tx_clk); + if (ret < 0) + pr_err("%s: afe lpass clock failed, err:%d\n", + __func__, ret); + break; + case 3: /*MSM_QUAT_MI2S*/ + mi2s_rx_clk.enable = 0; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_QUATERNARY_MI2S_RX, + &mi2s_rx_clk); + if (ret < 0) + pr_err("%s: afe lpass clock failed, err:%d\n", + __func__, ret); + break; + default: + pr_err("%s: invalid cpu_dai id 0x%x\n", __func__, cpu_dai->id); + break; + } +} + +static struct snd_soc_ops apq8096_mi2s_be_ops = { + .startup = apq8096_mi2s_snd_startup, + .shutdown = apq8096_mi2s_snd_shutdown, +}; + +static unsigned int tdm_param_set_slot_mask(u16 port_id, + int slot_width, int slots) +{ + unsigned int slot_mask = 0; + int upper, lower, i, j; + unsigned int *slot_offset; + + switch (port_id) { + case AFE_PORT_ID_SECONDARY_TDM_RX: + case AFE_PORT_ID_SECONDARY_TDM_RX_1: + case AFE_PORT_ID_SECONDARY_TDM_RX_2: + case AFE_PORT_ID_SECONDARY_TDM_RX_3: + case AFE_PORT_ID_SECONDARY_TDM_RX_4: + case AFE_PORT_ID_SECONDARY_TDM_RX_5: + case AFE_PORT_ID_SECONDARY_TDM_RX_6: + case AFE_PORT_ID_SECONDARY_TDM_RX_7: + lower = SECONDARY_TDM_RX_0; + upper = SECONDARY_TDM_RX_7; + break; + case AFE_PORT_ID_SECONDARY_TDM_TX: + case AFE_PORT_ID_SECONDARY_TDM_TX_1: + case AFE_PORT_ID_SECONDARY_TDM_TX_2: + case AFE_PORT_ID_SECONDARY_TDM_TX_3: + case AFE_PORT_ID_SECONDARY_TDM_TX_4: + case AFE_PORT_ID_SECONDARY_TDM_TX_5: + case AFE_PORT_ID_SECONDARY_TDM_TX_6: + case AFE_PORT_ID_SECONDARY_TDM_TX_7: + lower = SECONDARY_TDM_TX_0; + upper = SECONDARY_TDM_TX_7; + break; + case AFE_PORT_ID_TERTIARY_TDM_RX: + case AFE_PORT_ID_TERTIARY_TDM_RX_1: + case AFE_PORT_ID_TERTIARY_TDM_RX_2: + case AFE_PORT_ID_TERTIARY_TDM_RX_3: + case AFE_PORT_ID_TERTIARY_TDM_RX_4: + case AFE_PORT_ID_TERTIARY_TDM_RX_5: + case AFE_PORT_ID_TERTIARY_TDM_RX_6: + case AFE_PORT_ID_TERTIARY_TDM_RX_7: + lower = TERTIARY_TDM_RX_0; + upper = TERTIARY_TDM_RX_7; + break; + case AFE_PORT_ID_TERTIARY_TDM_TX: + case AFE_PORT_ID_TERTIARY_TDM_TX_1: + case AFE_PORT_ID_TERTIARY_TDM_TX_2: + case AFE_PORT_ID_TERTIARY_TDM_TX_3: + case AFE_PORT_ID_TERTIARY_TDM_TX_4: + case AFE_PORT_ID_TERTIARY_TDM_TX_5: + case AFE_PORT_ID_TERTIARY_TDM_TX_6: + case AFE_PORT_ID_TERTIARY_TDM_TX_7: + lower = TERTIARY_TDM_TX_0; + upper = TERTIARY_TDM_TX_7; break; - case 3: /*MSM_QUAT_MI2S*/ - mi2s_rx_clk.enable = 0; - ret = afe_set_lpass_clock_v2(AFE_PORT_ID_QUATERNARY_MI2S_RX, - &mi2s_rx_clk); - if (ret < 0) - pr_err("%s: afe lpass clock failed, err:%d\n", - __func__, ret); + case AFE_PORT_ID_QUATERNARY_TDM_RX: + case AFE_PORT_ID_QUATERNARY_TDM_RX_1: + case AFE_PORT_ID_QUATERNARY_TDM_RX_2: + case AFE_PORT_ID_QUATERNARY_TDM_RX_3: + case AFE_PORT_ID_QUATERNARY_TDM_RX_4: + case AFE_PORT_ID_QUATERNARY_TDM_RX_5: + case AFE_PORT_ID_QUATERNARY_TDM_RX_6: + case AFE_PORT_ID_QUATERNARY_TDM_RX_7: + lower = QUATERNARY_TDM_RX_0; + upper = QUATERNARY_TDM_RX_7; break; - default: - pr_err("%s: invalid cpu_dai id 0x%x\n", __func__, cpu_dai->id); + case AFE_PORT_ID_QUATERNARY_TDM_TX: + case AFE_PORT_ID_QUATERNARY_TDM_TX_1: + case AFE_PORT_ID_QUATERNARY_TDM_TX_2: + case AFE_PORT_ID_QUATERNARY_TDM_TX_3: + case AFE_PORT_ID_QUATERNARY_TDM_TX_4: + case AFE_PORT_ID_QUATERNARY_TDM_TX_5: + case AFE_PORT_ID_QUATERNARY_TDM_TX_6: + case AFE_PORT_ID_QUATERNARY_TDM_TX_7: + lower = QUATERNARY_TDM_TX_0; + upper = QUATERNARY_TDM_TX_7; break; + default: + return slot_mask; } -} - -static struct snd_soc_ops apq8096_mi2s_be_ops = { - .startup = apq8096_mi2s_snd_startup, - .shutdown = apq8096_mi2s_snd_shutdown, -}; - -static unsigned int tdm_param_set_slot_mask(int slots) -{ - unsigned int slot_mask = 0; - unsigned int i = 0; - if ((slots != 16) && (slots != 8)) { - pr_err("%s: invalid slot number %d\n", __func__, slots); - return -EINVAL; + for (i = lower; i <= upper; i++) { + slot_offset = tdm_slot_offset[i]; + for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) { + if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID) + /* + * set the mask of active slot according to + * the offset table for the group of devices + */ + slot_mask |= + (1 << ((slot_offset[j] * 8) / slot_width)); + else + break; + } } - for (i = 0; i < slots ; i++) - slot_mask |= 1 << i; return slot_mask; } @@ -3055,16 +2402,14 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; - int channels, slot_width, slots, rate; + int channels, slot_width, slots; unsigned int slot_mask; unsigned int *slot_offset; int offset_channels = 0; int i; - int clk_freq; pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); - rate = params_rate(params); channels = params_channels(params); if (channels < 1 || channels > 8) { pr_err("%s: invalid param channels %d\n", @@ -3090,88 +2435,15 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, } slots = msm_tdm_num_slots; + slot_mask = tdm_param_set_slot_mask(cpu_dai->id, + slot_width, slots); + if (!slot_mask) { + pr_err("%s: invalid slot_mask 0x%x\n", + __func__, slot_mask); + return -EINVAL; + } switch (cpu_dai->id) { - case AFE_PORT_ID_PRIMARY_TDM_RX: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_0]; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_1: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_1]; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_2: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_2]; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_3: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_3]; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_4: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_4]; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_5: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_5]; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_6: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_6]; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX_7: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_RX_7]; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_0]; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_1: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_1]; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_2: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_2]; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_3: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_3]; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_4: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_4]; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_5: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_5]; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_6: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_6]; - break; - case AFE_PORT_ID_PRIMARY_TDM_TX_7: - slots = msm_pri_tdm_slot_num; - slot_width = msm_pri_tdm_slot_width; - slot_offset = tdm_slot_offset[PRIMARY_TDM_TX_7]; - break; case AFE_PORT_ID_SECONDARY_TDM_RX: slot_offset = tdm_slot_offset[SECONDARY_TDM_RX_0]; break; @@ -3341,13 +2613,6 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - slot_mask = tdm_param_set_slot_mask(slots); - if (!slot_mask) { - pr_err("%s: invalid slot_mask 0x%x\n", - __func__, slot_mask); - return -EINVAL; - } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask, slots, slot_width); @@ -3382,13 +2647,6 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, } } - clk_freq = rate * slot_width * slots; - ret = snd_soc_dai_set_sysclk(cpu_dai, 0, clk_freq, SND_SOC_CLOCK_OUT); - if (ret < 0) { - pr_err("%s: failed to set tdm clk, err:%d\n", - __func__, ret); - } - end: return ret; } @@ -3410,9 +2668,6 @@ static const struct soc_enum msm_snd_enum[] = { SOC_ENUM_SINGLE_EXT(3, ec_ref_bit_format_text), SOC_ENUM_SINGLE_EXT(9, ec_ref_rate_text), SOC_ENUM_SINGLE_EXT(3, mi2s_rate_text), - SOC_ENUM_SINGLE_EXT(3, pri_tdm_rate_text), - SOC_ENUM_SINGLE_EXT(6, pri_tdm_slot_num_text), - SOC_ENUM_SINGLE_EXT(3, pri_tdm_slot_width_text), }; static const struct snd_kcontrol_new msm_snd_controls[] = { @@ -3426,22 +2681,6 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_proxy_rx_ch_get, msm_proxy_rx_ch_put), SOC_ENUM_EXT("HDMI_RX SampleRate", msm_snd_enum[4], hdmi_rx_sample_rate_get, hdmi_rx_sample_rate_put), - SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", msm_snd_enum[5], - msm_pri_tdm_tx_0_ch_get, msm_pri_tdm_tx_0_ch_put), - SOC_ENUM_EXT("PRI_TDM_TX_1 Channels", msm_snd_enum[5], - msm_pri_tdm_tx_1_ch_get, msm_pri_tdm_tx_1_ch_put), - SOC_ENUM_EXT("PRI_TDM_TX_2 Channels", msm_snd_enum[5], - msm_pri_tdm_tx_2_ch_get, msm_pri_tdm_tx_2_ch_put), - SOC_ENUM_EXT("PRI_TDM_TX_3 Channels", msm_snd_enum[5], - msm_pri_tdm_tx_3_ch_get, msm_pri_tdm_tx_3_ch_put), - SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", msm_snd_enum[5], - msm_pri_tdm_rx_0_ch_get, msm_pri_tdm_rx_0_ch_put), - SOC_ENUM_EXT("PRI_TDM_RX_1 Channels", msm_snd_enum[5], - msm_pri_tdm_rx_1_ch_get, msm_pri_tdm_rx_1_ch_put), - SOC_ENUM_EXT("PRI_TDM_RX_2 Channels", msm_snd_enum[5], - msm_pri_tdm_rx_2_ch_get, msm_pri_tdm_rx_2_ch_put), - SOC_ENUM_EXT("PRI_TDM_RX_3 Channels", msm_snd_enum[5], - msm_pri_tdm_rx_3_ch_get, msm_pri_tdm_rx_3_ch_put), SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", msm_snd_enum[5], msm_sec_tdm_tx_0_ch_get, msm_sec_tdm_tx_0_ch_put), SOC_ENUM_EXT("SEC_TDM_TX_1 Channels", msm_snd_enum[5], @@ -3484,30 +2723,6 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_quat_tdm_tx_2_ch_get, msm_quat_tdm_tx_2_ch_put), SOC_ENUM_EXT("QUAT_TDM_TX_3 Channels", msm_snd_enum[5], msm_quat_tdm_tx_3_ch_get, msm_quat_tdm_tx_3_ch_put), - SOC_ENUM_EXT("PRI_TDM_TX_0 Bit Format", msm_snd_enum[6], - msm_pri_tdm_tx_0_bit_format_get, - msm_pri_tdm_tx_0_bit_format_put), - SOC_ENUM_EXT("PRI_TDM_TX_1 Bit Format", msm_snd_enum[6], - msm_pri_tdm_tx_1_bit_format_get, - msm_pri_tdm_tx_1_bit_format_put), - SOC_ENUM_EXT("PRI_TDM_TX_2 Bit Format", msm_snd_enum[6], - msm_pri_tdm_tx_2_bit_format_get, - msm_pri_tdm_tx_2_bit_format_put), - SOC_ENUM_EXT("PRI_TDM_TX_3 Bit Format", msm_snd_enum[6], - msm_pri_tdm_tx_3_bit_format_get, - msm_pri_tdm_tx_3_bit_format_put), - SOC_ENUM_EXT("PRI_TDM_RX_0 Bit Format", msm_snd_enum[6], - msm_pri_tdm_rx_0_bit_format_get, - msm_pri_tdm_rx_0_bit_format_put), - SOC_ENUM_EXT("PRI_TDM_RX_1 Bit Format", msm_snd_enum[6], - msm_pri_tdm_rx_1_bit_format_get, - msm_pri_tdm_rx_1_bit_format_put), - SOC_ENUM_EXT("PRI_TDM_RX_2 Bit Format", msm_snd_enum[6], - msm_pri_tdm_rx_2_bit_format_get, - msm_pri_tdm_rx_2_bit_format_put), - SOC_ENUM_EXT("PRI_TDM_RX_3 Bit Format", msm_snd_enum[6], - msm_pri_tdm_rx_3_bit_format_get, - msm_pri_tdm_rx_3_bit_format_put), SOC_ENUM_EXT("SEC_TDM_TX_0 Bit Format", msm_snd_enum[6], msm_sec_tdm_tx_0_bit_format_get, msm_sec_tdm_tx_0_bit_format_put), @@ -3582,268 +2797,6 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_sec_mi2s_tx_bit_format_put), SOC_ENUM_EXT("SEC_MI2S_TX SampleRate", msm_snd_enum[11], msm_sec_mi2s_rate_get, msm_sec_mi2s_rate_put), - SOC_ENUM_EXT("PRI_TDM SampleRate", msm_snd_enum[12], - msm_pri_tdm_rate_get, msm_pri_tdm_rate_put), - SOC_ENUM_EXT("PRI_TDM Slot Number", msm_snd_enum[13], - msm_pri_tdm_slot_num_get, msm_pri_tdm_slot_num_put), - SOC_ENUM_EXT("PRI_TDM Slot Width", msm_snd_enum[14], - msm_pri_tdm_slot_width_get, msm_pri_tdm_slot_width_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_0 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_RX_0, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_1 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_RX_1, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_2 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_RX_2, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_3 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_RX_3, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_4 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_RX_4, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_5 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_RX_5, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_6 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_RX_6, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_7 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_RX_7, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_0 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_TX_0, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_1 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_TX_1, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_2 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_TX_2, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_3 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_TX_3, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_4 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_TX_4, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_5 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_TX_5, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_6 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_TX_6, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_7 Slot Mapping", SND_SOC_NOPM, - PRIMARY_TDM_TX_7, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_0 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_RX_0, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_1 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_RX_1, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_2 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_RX_2, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_3 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_RX_3, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_4 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_RX_4, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_5 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_RX_5, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_6 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_RX_6, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_7 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_RX_7, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_0 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_TX_0, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_1 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_TX_1, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_2 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_TX_2, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_3 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_TX_3, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_4 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_TX_4, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_5 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_TX_5, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_6 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_TX_6, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_7 Slot Mapping", SND_SOC_NOPM, - SECONDARY_TDM_TX_7, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_0 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_RX_0, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_1 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_RX_1, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_2 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_RX_2, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_3 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_RX_3, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_4 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_RX_4, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_5 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_RX_5, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_6 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_RX_6, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_7 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_RX_7, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_0 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_TX_0, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_1 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_TX_1, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_2 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_TX_2, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_3 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_TX_3, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_4 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_TX_4, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_5 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_TX_5, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_6 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_TX_6, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_7 Slot Mapping", SND_SOC_NOPM, - TERTIARY_TDM_TX_7, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_0 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_RX_0, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_1 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_RX_1, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_2 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_RX_2, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_3 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_RX_3, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_4 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_RX_4, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_5 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_RX_5, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_6 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_RX_6, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_7 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_RX_7, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_0 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_TX_0, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_1 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_TX_1, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_2 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_TX_2, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_3 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_TX_3, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_4 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_TX_4, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_5 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_TX_5, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_6 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_TX_6, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), - SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_7 Slot Mapping", SND_SOC_NOPM, - QUATERNARY_TDM_TX_7, 0xFFFF, - 0, 8, msm_tdm_slot_mapping_get, - msm_tdm_slot_mapping_put), SOC_ENUM_EXT("EC Reference Channels", msm_snd_enum[8], msm_ec_ref_ch_get, msm_ec_ref_ch_put), SOC_ENUM_EXT("EC Reference Bit Format", msm_snd_enum[9], @@ -4091,22 +3044,21 @@ static struct snd_soc_dai_link apq8096_common_dai_links[] = { .codec_name = "snd-soc-dummy", }, { - .name = "MSM8996 HFP RX", - .stream_name = "MultiMedia21", - .cpu_dai_name = "MultiMedia21", - .platform_name = "msm-pcm-loopback", + .name = "SLIMBUS_4 Hostless", + .stream_name = "SLIMBUS_4 Hostless", + .cpu_dai_name = "SLIMBUS4_HOSTLESS", + .platform_name = "msm-pcm-hostless", .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .ignore_suspend = 1, .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - /* this dainlink has playback support */ + .ignore_suspend = 1, + /* this dailink has playback support */ .ignore_pmdown_time = 1, - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA21, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", }, { .name = "VoLTE", @@ -4528,13 +3480,12 @@ static struct snd_soc_dai_link apq8096_common_dai_links[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, { - .name = "MSM8996 ULL NOIRQ 2", - .stream_name = "MM_NOIRQ_2", + .name = "MSM8996 Compress9", + .stream_name = "Compress9", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-pcm-dsp-noirq", + .platform_name = "msm-compress-dsp", .dynamic = 1, .dpcm_playback = 1, - .dpcm_capture = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .codec_dai_name = "snd-soc-dummy-dai", @@ -4853,126 +3804,6 @@ static struct snd_soc_dai_link apq8096_auto_fe_dai_links[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, - { - .name = "Primary TDM RX 0 Hostless", - .stream_name = "Primary TDM RX 0 Hostless", - .cpu_dai_name = "PRI_TDM_RX_0_HOSTLESS", - .platform_name = "msm-pcm-hostless", - .dynamic = 1, - .dpcm_playback = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - }, - { - .name = "Primary TDM RX 1 Hostless", - .stream_name = "Primary TDM RX 1 Hostless", - .cpu_dai_name = "PRI_TDM_RX_1_HOSTLESS", - .platform_name = "msm-pcm-hostless", - .dynamic = 1, - .dpcm_playback = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - }, - { - .name = "Primary TDM RX 2 Hostless", - .stream_name = "Primary TDM RX 2 Hostless", - .cpu_dai_name = "PRI_TDM_RX_2_HOSTLESS", - .platform_name = "msm-pcm-hostless", - .dynamic = 1, - .dpcm_playback = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - }, - { - .name = "Primary TDM RX 3 Hostless", - .stream_name = "Primary TDM RX 3 Hostless", - .cpu_dai_name = "PRI_TDM_RX_3_HOSTLESS", - .platform_name = "msm-pcm-hostless", - .dynamic = 1, - .dpcm_playback = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - }, - { - .name = "Primary TDM TX 0 Hostless", - .stream_name = "Primary TDM TX 0 Hostless", - .cpu_dai_name = "PRI_TDM_TX_0_HOSTLESS", - .platform_name = "msm-pcm-hostless", - .dynamic = 1, - .dpcm_capture = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - }, - { - .name = "Primary TDM TX 1 Hostless", - .stream_name = "Primary TDM TX 1 Hostless", - .cpu_dai_name = "PRI_TDM_TX_1_HOSTLESS", - .platform_name = "msm-pcm-hostless", - .dynamic = 1, - .dpcm_capture = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - }, - { - .name = "Primary TDM TX 2 Hostless", - .stream_name = "Primary TDM TX 2 Hostless", - .cpu_dai_name = "PRI_TDM_TX_2_HOSTLESS", - .platform_name = "msm-pcm-hostless", - .dynamic = 1, - .dpcm_capture = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - }, - { - .name = "Primary TDM TX 3 Hostless", - .stream_name = "Primary TDM TX 3 Hostless", - .cpu_dai_name = "PRI_TDM_TX_3_HOSTLESS", - .platform_name = "msm-pcm-hostless", - .dynamic = 1, - .dpcm_capture = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - } }; static struct snd_soc_dai_link apq8096_custom_fe_dai_links[] = { @@ -5619,118 +4450,6 @@ static struct snd_soc_dai_link apq8096_auto_be_dai_links[] = { .ops = &apq8096_tdm_be_ops, .ignore_suspend = 1, }, - { - .name = LPASS_BE_PRI_TDM_RX_0, - .stream_name = "Primary TDM0 Playback", - .cpu_dai_name = "msm-dai-q6-tdm.36864", - .platform_name = "msm-pcm-routing", - .codec_name = "msm-stub-codec.1", - .codec_dai_name = "msm-stub-rx", - .no_pcm = 1, - .dpcm_playback = 1, - .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0, - .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, - .ops = &apq8096_tdm_be_ops, - .ignore_suspend = 1, - }, - { - .name = LPASS_BE_PRI_TDM_RX_1, - .stream_name = "Primary TDM1 Playback", - .cpu_dai_name = "msm-dai-q6-tdm.36866", - .platform_name = "msm-pcm-routing", - .codec_name = "msm-stub-codec.1", - .codec_dai_name = "msm-stub-rx", - .no_pcm = 1, - .dpcm_playback = 1, - .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_1, - .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, - .ops = &apq8096_tdm_be_ops, - .ignore_suspend = 1, - }, - { - .name = LPASS_BE_PRI_TDM_RX_2, - .stream_name = "Primary TDM2 Playback", - .cpu_dai_name = "msm-dai-q6-tdm.36868", - .platform_name = "msm-pcm-routing", - .codec_name = "msm-stub-codec.1", - .codec_dai_name = "msm-stub-rx", - .no_pcm = 1, - .dpcm_playback = 1, - .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_2, - .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, - .ops = &apq8096_tdm_be_ops, - .ignore_suspend = 1, - }, - { - .name = LPASS_BE_PRI_TDM_RX_3, - .stream_name = "Primary TDM3 Playback", - .cpu_dai_name = "msm-dai-q6-tdm.36870", - .platform_name = "msm-pcm-routing", - .codec_name = "msm-stub-codec.1", - .codec_dai_name = "msm-stub-rx", - .no_pcm = 1, - .dpcm_playback = 1, - .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_3, - .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, - .ops = &apq8096_tdm_be_ops, - .ignore_suspend = 1, - }, - { - .name = LPASS_BE_PRI_TDM_TX_0, - .stream_name = "Primary TDM0 Capture", - .cpu_dai_name = "msm-dai-q6-tdm.36865", - .platform_name = "msm-pcm-routing", - .codec_name = "msm-stub-codec.1", - .codec_dai_name = "msm-stub-rx", - .no_pcm = 1, - .dpcm_capture = 1, - .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0, - .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, - .ops = &apq8096_tdm_be_ops, - .ignore_suspend = 1, - }, - { - .name = LPASS_BE_PRI_TDM_TX_1, - .stream_name = "Primary TDM1 Capture", - .cpu_dai_name = "msm-dai-q6-tdm.36867", - .platform_name = "msm-pcm-routing", - .codec_name = "msm-stub-codec.1", - .codec_dai_name = "msm-stub-rx", - .no_pcm = 1, - .dpcm_capture = 1, - .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_1, - .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, - .ops = &apq8096_tdm_be_ops, - .ignore_suspend = 1, - }, - { - .name = LPASS_BE_PRI_TDM_TX_2, - .stream_name = "Primary TDM2 Capture", - .cpu_dai_name = "msm-dai-q6-tdm.36869", - .platform_name = "msm-pcm-routing", - .codec_name = "msm-stub-codec.1", - .codec_dai_name = "msm-stub-rx", - .no_pcm = 1, - .dpcm_capture = 1, - .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_2, - .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, - .ops = &apq8096_tdm_be_ops, - .ignore_suspend = 1, - }, - { - .name = LPASS_BE_PRI_TDM_TX_3, - .stream_name = "Primary TDM3 Capture", - .cpu_dai_name = "msm-dai-q6-tdm.36871", - .platform_name = "msm-pcm-routing", - .codec_name = "msm-stub-codec.1", - .codec_dai_name = "msm-stub-rx", - .no_pcm = 1, - .dpcm_capture = 1, - .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_3, - .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, - .ops = &apq8096_tdm_be_ops, - .ignore_suspend = 1, - } }; static struct snd_soc_dai_link apq8096_hdmi_dai_link[] = { @@ -6074,6 +4793,7 @@ static int apq8096_asoc_machine_probe(struct platform_device *pdev) goto err; } dev_info(&pdev->dev, "Sound card %s registered\n", card->name); + return 0; err: diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c index 5facafdc7729c38f2c124af0b4d4d5f11e42905b..24dbbedf0be787e29510d189bd94333944ed0383 100644 --- a/sound/soc/msm/msm-dai-fe.c +++ b/sound/soc/msm/msm-dai-fe.c @@ -2496,21 +2496,8 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .rate_min = 8000, .rate_max = 384000, }, - .capture = { - .stream_name = "MultiMedia16 Capture", - .aif_name = "MM_UL16", - .rates = (SNDRV_PCM_RATE_8000_48000| - SNDRV_PCM_RATE_KNOT), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE), - .channels_min = 1, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 48000, - }, .ops = &msm_fe_Multimedia_dai_ops, + .compress_new = snd_soc_new_compress, .name = "MultiMedia16", .probe = fe_dai_probe, }, @@ -2654,154 +2641,6 @@ static struct snd_soc_dai_driver msm_fe_dais[] = { .name = "MultiMedia20", .probe = fe_dai_probe, }, - { - .playback = { - .stream_name = "MultiMedia21 Playback", - .aif_name = "MM_DL21", - .rates = (SNDRV_PCM_RATE_8000_384000 | - SNDRV_PCM_RATE_KNOT), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE), - .channels_min = 1, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 384000, - }, - .capture = { - .stream_name = "MultiMedia21 Capture", - .aif_name = "MM_UL21", - .rates = (SNDRV_PCM_RATE_8000_48000| - SNDRV_PCM_RATE_KNOT), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE), - .channels_min = 1, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 48000, - }, - .ops = &msm_fe_Multimedia_dai_ops, - .name = "MultiMedia21", - .probe = fe_dai_probe, - }, - { - .playback = { - .stream_name = "MultiMedia22 Playback", - .aif_name = "MM_DL22", - .rates = (SNDRV_PCM_RATE_8000_384000 | - SNDRV_PCM_RATE_KNOT), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE), - .channels_min = 1, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 384000, - }, - .ops = &msm_fe_Multimedia_dai_ops, - .name = "MultiMedia22", - .probe = fe_dai_probe, - }, - { - .playback = { - .stream_name = "MultiMedia23 Playback", - .aif_name = "MM_DL23", - .rates = (SNDRV_PCM_RATE_8000_384000 | - SNDRV_PCM_RATE_KNOT), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE), - .channels_min = 1, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 384000, - }, - .ops = &msm_fe_Multimedia_dai_ops, - .name = "MultiMedia23", - .probe = fe_dai_probe, - }, - { - .playback = { - .stream_name = "MultiMedia24 Playback", - .aif_name = "MM_DL24", - .rates = (SNDRV_PCM_RATE_8000_384000 | - SNDRV_PCM_RATE_KNOT), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE), - .channels_min = 1, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 384000, - }, - .ops = &msm_fe_Multimedia_dai_ops, - .name = "MultiMedia24", - .probe = fe_dai_probe, - }, - { - .playback = { - .stream_name = "MultiMedia25 Playback", - .aif_name = "MM_DL25", - .rates = (SNDRV_PCM_RATE_8000_384000 | - SNDRV_PCM_RATE_KNOT), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE), - .channels_min = 1, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 384000, - }, - .ops = &msm_fe_Multimedia_dai_ops, - .name = "MultiMedia25", - .probe = fe_dai_probe, - }, - { - .playback = { - .stream_name = "MultiMedia26 Playback", - .aif_name = "MM_DL26", - .rates = (SNDRV_PCM_RATE_8000_384000 | - SNDRV_PCM_RATE_KNOT), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE), - .channels_min = 1, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 384000, - }, - .ops = &msm_fe_Multimedia_dai_ops, - .compress_new = snd_soc_new_compress, - .name = "MultiMedia26", - .probe = fe_dai_probe, - }, - { - .capture = { - .stream_name = "MultiMedia27 Capture", - .aif_name = "MM_UL27", - .rates = (SNDRV_PCM_RATE_8000_192000| - SNDRV_PCM_RATE_KNOT), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S24_3LE), - .channels_min = 1, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 192000, - }, - .ops = &msm_fe_Multimedia_dai_ops, - .compress_new = snd_soc_new_compress, - .name = "MultiMedia27", - .probe = fe_dai_probe, - }, }; static int msm_fe_dai_dev_probe(struct platform_device *pdev) diff --git a/sound/soc/msm/msm-pcm-hostless.c b/sound/soc/msm/msm-pcm-hostless.c index 51b0a7208462994117edc8f0d461fcafb8526fe4..57932433afe99f065fd3bc2168d6dfcaa6c1bd12 100644 --- a/sound/soc/msm/msm-pcm-hostless.c +++ b/sound/soc/msm/msm-pcm-hostless.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, 2017 The Linux Foundation. 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 and @@ -25,9 +25,7 @@ static int msm_pcm_hostless_prepare(struct snd_pcm_substream *substream) pr_err("%s: invalid params\n", __func__); return -EINVAL; } - if (pm_qos_request_active(&substream->latency_pm_qos_req)) - pm_qos_remove_request(&substream->latency_pm_qos_req); - + pm_qos_remove_request(&substream->latency_pm_qos_req); return 0; } diff --git a/sound/soc/msm/msm8996.c b/sound/soc/msm/msm8996.c index 010dfa3322a056873aff1159b10b2ab611269fc7..4eafd322d50dd609557acd16920e12ae37e70e17 100644 --- a/sound/soc/msm/msm8996.c +++ b/sound/soc/msm/msm8996.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016, 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 @@ -2910,13 +2910,12 @@ static struct snd_soc_dai_link msm8996_common_dai_links[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, { - .name = "MSM8996 ULL NOIRQ_2", - .stream_name = "MM_NOIRQ_2", + .name = "MSM8996 Compress9", + .stream_name = "Compress9", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-pcm-dsp-noirq", + .platform_name = "msm-compress-dsp", .dynamic = 1, .dpcm_playback = 1, - .dpcm_capture = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .codec_dai_name = "snd-soc-dummy-dai", diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c index 9159ea6428162381cbae81c290adbeb86c00be2e..e75084d113d84490c6c3441663c19cc6e53081f4 100644 --- a/sound/soc/msm/msm8998.c +++ b/sound/soc/msm/msm8998.c @@ -10,6 +10,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -177,6 +182,7 @@ struct msm_pinctrl_info { struct msm_asoc_mach_data { u32 mclk_freq; int us_euro_gpio; /* used by gpio driver API */ + int ear_en_gpio; struct device_node *us_euro_gpio_p; /* used by pinctrl API */ struct device_node *hph_en1_gpio_p; /* used by pinctrl API */ struct device_node *hph_en0_gpio_p; /* used by pinctrl API */ @@ -397,9 +403,8 @@ static struct dev_config aux_pcm_tx_cfg[] = { }; static int msm_vi_feed_tx_ch = 2; -static const char *const slim_rx_ch_text[] = {"One", "Two", "Three", "Four", - "Five", "Six", "Seven", - "Eight"}; +static int ear_enable_states; +static const char *const slim_rx_ch_text[] = {"One", "Two"}; static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; @@ -434,12 +439,12 @@ static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32", static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"}; static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32", "KHZ_44P1", "KHZ_48", - "KHZ_88P2", "KHZ_96", "KHZ_176P4", - "KHZ_192"}; + "KHZ_96", "KHZ_192"}; static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; static const char *const hifi_text[] = {"Off", "On"}; +static const char *const ear_enable_states_text[] = {"Disable", "Enable"}; static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text); @@ -502,6 +507,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(mi2s_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(hifi_function, hifi_text); +static SOC_ENUM_SINGLE_EXT_DECL(ear_enable_state, ear_enable_states_text); static struct platform_device *spdev; static int msm_hifi_control; @@ -539,9 +545,8 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { .key_code[7] = 0, .linein_th = 5000, .moisture_en = true, - .mbhc_micbias = MIC_BIAS_2, - .anc_micbias = MIC_BIAS_2, - .enable_anc_mic_detect = false, + .anc_micbias = MIC_BIAS_3, + .enable_anc_mic_detect = true, }; static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = { @@ -558,13 +563,6 @@ static struct snd_soc_dapm_route wcd_audio_paths[] = { {"MIC BIAS4", NULL, "MCLK"}, }; -static u32 mi2s_ebit_clk[MI2S_MAX] = { - Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT, - Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT, - Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT, - Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT, -}; - static struct afe_clk_set mi2s_clk[MI2S_MAX] = { { AFE_API_VERSION_I2S_CONFIG, @@ -1404,6 +1402,61 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, return rc; } +static int ear_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int gpio_state = 0; + + switch (ear_enable_states) { + case 1: + gpio_state = 1; + break; + case 0: + default: + gpio_state = 0; + break; + } + + ucontrol->value.integer.value[0] = gpio_state; + pr_debug("%s: ear_enable_states = %d\n", __func__, + ear_enable_states); + + return 0; +} + +static int ear_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + struct snd_soc_card *card = platform_get_drvdata(spdev); + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + pr_debug("%s: ucontrol value = %ld\n", __func__, + ucontrol->value.integer.value[0]); + + if (pdata->ear_en_gpio >= 0) { + ret = gpio_request(pdata->ear_en_gpio, "ear_en_gpio"); + if (ret) { + pr_err("%s: request ear_en_gpio failed, ret:%d\n", + __func__, ret); + return ret; + } + switch (ucontrol->value.integer.value[0]) { + case 1: + gpio_set_value(pdata->ear_en_gpio, 1); + break; + case 0: + default: + gpio_set_value(pdata->ear_en_gpio, 0); + break; + } + gpio_free(pdata->ear_en_gpio); + ear_enable_states = ucontrol->value.integer.value[0]; + } + + return 0; +} + static int ext_disp_get_port_idx(struct snd_kcontrol *kcontrol) { int idx; @@ -2229,17 +2282,11 @@ static int mi2s_get_sample_rate_val(int sample_rate) case SAMPLING_RATE_48KHZ: sample_rate_val = 4; break; - case SAMPLING_RATE_88P2KHZ: - sample_rate_val = 5; - break; case SAMPLING_RATE_96KHZ: - sample_rate_val = 6; - break; - case SAMPLING_RATE_176P4KHZ: - sample_rate_val = 7; + sample_rate_val = 5; break; case SAMPLING_RATE_192KHZ: - sample_rate_val = 8; + sample_rate_val = 6; break; default: sample_rate_val = 4; @@ -2269,15 +2316,9 @@ static int mi2s_get_sample_rate(int value) sample_rate = SAMPLING_RATE_48KHZ; break; case 5: - sample_rate = SAMPLING_RATE_88P2KHZ; - break; - case 6: sample_rate = SAMPLING_RATE_96KHZ; break; - case 7: - sample_rate = SAMPLING_RATE_176P4KHZ; - break; - case 8: + case 6: sample_rate = SAMPLING_RATE_192KHZ; break; default: @@ -2809,6 +2850,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), SOC_ENUM_EXT("HiFi Function", hifi_function, msm_hifi_get, msm_hifi_put), + SOC_ENUM_EXT("Ear_Enable_States", ear_enable_state, + ear_enable_get, + ear_enable_put), }; static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, @@ -3766,7 +3810,7 @@ static void *def_tasha_mbhc_cal(void) (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn); btn_high[0] = 75; - btn_high[1] = 150; + btn_high[1] = 137; btn_high[2] = 237; btn_high[3] = 500; btn_high[4] = 500; @@ -4528,11 +4572,6 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) */ mutex_lock(&mi2s_intf_conf[index].lock); if (++mi2s_intf_conf[index].ref_cnt == 1) { - /* Check if msm needs to provide the clock to the interface */ - if (!mi2s_intf_conf[index].msm_is_mi2s_master) { - fmt = SND_SOC_DAIFMT_CBM_CFM; - mi2s_clk[index].clk_id = mi2s_ebit_clk[index]; - } ret = msm_mi2s_set_sclk(substream, true); if (IS_ERR_VALUE(ret)) { dev_err(rtd->card->dev, @@ -4552,6 +4591,9 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) ret = -EINVAL; goto clk_off; } + /* Check if msm needs to provide the clock to the interface */ + if (!mi2s_intf_conf[index].msm_is_mi2s_master) + fmt = SND_SOC_DAIFMT_CBM_CFM; ret = snd_soc_dai_set_fmt(cpu_dai, fmt); if (IS_ERR_VALUE(ret)) { pr_err("%s: set fmt cpu dai failed for MI2S (%d), err:%d\n", @@ -5328,13 +5370,12 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, { - .name = MSM_DAILINK_NAME(ULL_NOIRQ_2), - .stream_name = "MM_NOIRQ_2", + .name = MSM_DAILINK_NAME(Compress9), + .stream_name = "Compress9", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-pcm-dsp-noirq", + .platform_name = "msm-compress-dsp", .dynamic = 1, .dpcm_playback = 1, - .dpcm_capture = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .codec_dai_name = "snd-soc-dummy-dai", @@ -5520,122 +5561,6 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, - { - .name = MSM_DAILINK_NAME(Transcode Loopback Playback), - .stream_name = "Transcode Loopback Playback", - .cpu_dai_name = "MultiMedia26", - .platform_name = "msm-transcode-loopback", - .dynamic = 1, - .dpcm_playback = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - /* this dainlink has playback support */ - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA26, - }, - { - .name = MSM_DAILINK_NAME(Transcode Loopback Capture), - .stream_name = "Transcode Loopback Capture", - .cpu_dai_name = "MultiMedia27", - .platform_name = "msm-transcode-loopback", - .dynamic = 1, - .dpcm_capture = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA27, - }, - { - .name = "MultiMedia21", - .stream_name = "MultiMedia21", - .cpu_dai_name = "MultiMedia21", - .platform_name = "msm-pcm-dsp.0", - .dynamic = 1, - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, - .dpcm_playback = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA21, - }, - { - .name = "MultiMedia22", - .stream_name = "MultiMedia22", - .cpu_dai_name = "MultiMedia22", - .platform_name = "msm-pcm-dsp.0", - .dynamic = 1, - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, - .dpcm_playback = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA22, - }, - { - .name = "MultiMedia23", - .stream_name = "MultiMedia23", - .cpu_dai_name = "MultiMedia23", - .platform_name = "msm-pcm-dsp.0", - .dynamic = 1, - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, - .dpcm_playback = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA23, - }, - { - .name = "MultiMedia24", - .stream_name = "MultiMedia24", - .cpu_dai_name = "MultiMedia24", - .platform_name = "msm-pcm-dsp.0", - .dynamic = 1, - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, - .dpcm_playback = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA24, - }, - { - .name = "MultiMedia25", - .stream_name = "MultiMedia25", - .cpu_dai_name = "MultiMedia25", - .platform_name = "msm-pcm-dsp.0", - .dynamic = 1, - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, - .dpcm_playback = 1, - .codec_dai_name = "snd-soc-dummy-dai", - .codec_name = "snd-soc-dummy", - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, - .be_id = MSM_FRONTEND_DAI_MULTIMEDIA25, - }, }; static struct snd_soc_dai_link msm_common_be_dai_links[] = { @@ -7479,19 +7404,14 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) pdev->dev.of_node->full_name); dev_dbg(&pdev->dev, "Jack type properties set to default"); } else { - if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) { - wcd_mbhc_cfg.enable_anc_mic_detect = false; + if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) dev_dbg(&pdev->dev, "This hardware has 4 pole jack"); - } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) { - wcd_mbhc_cfg.enable_anc_mic_detect = true; + else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) dev_dbg(&pdev->dev, "This hardware has 5 pole jack"); - } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) { - wcd_mbhc_cfg.enable_anc_mic_detect = true; + else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) dev_dbg(&pdev->dev, "This hardware has 6 pole jack"); - } else { - wcd_mbhc_cfg.enable_anc_mic_detect = false; + else dev_dbg(&pdev->dev, "Unknown value, set to default"); - } } /* * Parse US-Euro gpio info from DT. Report no error if us-euro @@ -7537,6 +7457,17 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) pr_err("%s: Audio notifier register failed ret = %d\n", __func__, ret); + /* Parse EAR_EN info for NX5L2750C */ + pdata->ear_en_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,ear-en-gpios", 0); + if (pdata->ear_en_gpio < 0) { + dev_err(&pdev->dev, "property %s not detected in node %s", + "qcom,ear-en-gpios", + pdev->dev.of_node->full_name); + ret = -ENODEV; + goto err; + } + return 0; err: if (pdata->us_euro_gpio > 0) { @@ -7545,6 +7476,11 @@ err: gpio_free(pdata->us_euro_gpio); pdata->us_euro_gpio = 0; } + if (pdata->ear_en_gpio > 0) { + dev_dbg(&pdev->dev, "%s initialize ear_en gpio %d\n", + __func__, pdata->ear_en_gpio); + pdata->ear_en_gpio = 0; + } msm_release_pinctrl(pdev); devm_kfree(&pdev->dev, pdata); return ret; diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile index 98c52a4db51f1fd50e812b40bf15ddec4dd3d0f3..a10fb826bc629659dcc4cb4fee8a41495a2f5856 100644 --- a/sound/soc/msm/qdsp6v2/Makefile +++ b/sound/soc/msm/qdsp6v2/Makefile @@ -12,10 +12,12 @@ obj-$(CONFIG_SND_HWDEP) += msm-pcm-routing-devdep.o obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o obj-$(CONFIG_DOLBY_DS2) += msm-ds2-dap-config.o obj-$(CONFIG_DOLBY_LICENSE) += msm-ds2-dap-config.o +obj-$(CONFIG_AHC) += msm-ahc-config.o obj-$(CONFIG_DTS_SRS_TM) += msm-dts-srs-tm-config.o obj-$(CONFIG_QTI_PP) += msm-qti-pp-config.o obj-y += audio_calibration.o audio_cal_utils.o q6adm.o q6afe.o q6asm.o \ q6audio-v2.o q6voice.o q6core.o rtac.o q6lsm.o audio_slimslave.o \ - msm-pcm-q6-noirq.o + msm-pcm-q6-noirq.o \ + sony-hweffect-params.o msm-sony-hweffect.o ocmem-audio-objs += audio_ocmem.o obj-$(CONFIG_AUDIO_OCMEM) += ocmem-audio.o diff --git a/sound/soc/msm/qdsp6v2/msm-ahc-config.c b/sound/soc/msm/qdsp6v2/msm-ahc-config.c new file mode 100644 index 0000000000000000000000000000000000000000..04cbdeb2f7b23f2260e0411dcd489833c1dfc45a --- /dev/null +++ b/sound/soc/msm/qdsp6v2/msm-ahc-config.c @@ -0,0 +1,570 @@ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm-ahc-config.h" + +enum { + AHC_IIR_TF_REG_ENABLE = 0, + AHC_IIR_TF_REG_ENABLE_CONFIG, + AHC_IIR_TF_REG_PRE_GAIN, + AHC_IIR_TF_REG_CONFIG_PARAMS, + AHC_IIR_TF_REG_CONFIG_ALL_PARAMS, + AHC_MBDRC_REG_ENABLE, + AHC_MBDRC_REG_ENABLE_CONFIG, +}; + +enum { + AHC_IIR_TF_SHIFT_BAND1 = 0, + AHC_IIR_TF_SHIFT_BAND2, + AHC_IIR_TF_SHIFT_BAND3, + AHC_IIR_TF_SHIFT_BAND4, + AHC_IIR_TF_SHIFT_BAND5, +}; + +#define AHC_BANDS_USED 5 + +#define IIR_COEFF_CHANNEL_LEFT 0 +#define IIR_COEFF_CHANNEL_CENTER 1 +#define IIR_COEFF_CHANNEL_RIGHT 2 + +/* 1073741824 is Q30 format for 1.0 */ +#define DEFAULT_COEFF {1073741824, 0, 0, 0, 0} +#define START_COEFF_STRUCT {.coeff = DEFAULT_COEFF, .num_shift_factor = 2, \ + .pan_setting = IIR_COEFF_CHANNEL_CENTER} + +struct audproc_common_enable { + uint32_t enable; +} __packed; + +struct iir_tf_5_config { + struct asm_iir_filter_config_params bands; + int32_t coeffs[5][5]; + int16_t num_shift_factor[5]; + uint16_t pan_setting[5]; +} __packed; + +struct iir_tf_coeff { + int32_t coeff[5]; + int16_t num_shift_factor; + uint16_t pan_setting; +}; + +static struct iir_tf_coeff iir_tf_coeffs[AHC_BANDS_USED] = { + START_COEFF_STRUCT, START_COEFF_STRUCT, START_COEFF_STRUCT, + START_COEFF_STRUCT, START_COEFF_STRUCT +}; + +static int32_t default_coeff[5] = DEFAULT_COEFF; + +static int ahc_copp_idx = -1; + +static int iir_tf_send_params(int port_id, uint32_t module_id, + uint32_t param_id, uint8_t *param, uint32_t param_len) +{ + uint8_t *params_value; + struct adm_param_data_v5 *p_hdr; + uint32_t pkt_len = sizeof(*p_hdr) + param_len; + int rc; + + pr_debug("%s: module_id 0x%X param_id 0x%X param_len %d\n", + __func__, module_id, param_id, param_len); + + params_value = kmalloc(pkt_len, GFP_KERNEL); + if (!params_value) { + pr_err("%s, params memory alloc failed\n", __func__); + return -ENOMEM; + } + + p_hdr = (struct adm_param_data_v5 *)params_value; + p_hdr->module_id = module_id; + p_hdr->param_id = param_id; + p_hdr->param_size = param_len; + p_hdr->reserved = 0; + memcpy(params_value + sizeof(*p_hdr), param, param_len); + + rc = adm_ahc_send_params(port_id, ahc_copp_idx, params_value, + pkt_len); + if (rc) + pr_err("%s: send ahc params failed %d\n", __func__, rc); + + kfree(params_value); + return rc; +} + +static int send_iir_config(void) +{ + struct iir_tf_5_config *params; + int rc = 0, i, j; + + params = kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + pr_err("%s: Could not allocate params\n", __func__); + return -ENOMEM; + } + + params->bands.num_biquad_stages = AHC_BANDS_USED; + params->bands.reserved = 0; + + for (i = 0; i < AHC_BANDS_USED; i++) { + for (j = 0; j < 5; j++) + params->coeffs[i][j] = iir_tf_coeffs[i].coeff[j]; + params->num_shift_factor[i] = + iir_tf_coeffs[i].num_shift_factor; + params->pan_setting[i] = iir_tf_coeffs[i].pan_setting; + } + + rc = iir_tf_send_params(AHC_PORT_ID, + ASM_MODULE_ID_IIRUNING_FILTER, + ASM_PARAM_ID_IIRUNING_FILTER_CONFIG_PARAMS, + (uint8_t *)params, sizeof(*params)); + + kfree(params); + return rc; +} + +static int get_params_for_get_cmd(int cmd, int band, int *param_len, + uint32_t *param_id, uint32_t *module_id) +{ + switch (cmd) { + case AHC_IIR_TF_REG_ENABLE: + pr_debug("%s: AHC_IIR_TF_REG_ENABLE\n", __func__); + *param_len = sizeof(struct audproc_common_enable); + *param_id = AUDPROC_PARAM_ID_ENABLE; + *module_id = ASM_MODULE_ID_IIRUNING_FILTER; + break; + + case AHC_IIR_TF_REG_ENABLE_CONFIG: + pr_debug("%s: AHC_IIR_TF_REG_ENABLE_CONFIG\n", __func__); + *param_len = sizeof(struct asm_iiruning_filter_enable); + *param_id = ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CONFIG; + *module_id = ASM_MODULE_ID_IIRUNING_FILTER; + break; + + case AHC_IIR_TF_REG_PRE_GAIN: + pr_debug("%s: AHC_IIR_TF_REG_PRE_GAIN\n", __func__); + *param_len = sizeof(struct asm_iiruning_filter_pregain); + *param_id = ASM_PARAM_ID_IIRUNING_FILTER_PRE_GAIN; + *module_id = ASM_MODULE_ID_IIRUNING_FILTER; + break; + + case AHC_IIR_TF_REG_CONFIG_PARAMS: + pr_debug("%s: AHC_IIR_TF_REG_CONFIG_PARAMS for band %d\n", + __func__, band); + *param_len = sizeof(struct iir_tf_5_config); + *param_id = ASM_PARAM_ID_IIRUNING_FILTER_CONFIG_PARAMS; + *module_id = ASM_MODULE_ID_IIRUNING_FILTER; + break; + + case AHC_IIR_TF_REG_CONFIG_ALL_PARAMS: + pr_debug("%s: AHC_IIR_TF_REG_CONFIG_ALL_PARAMS\n", __func__); + *param_len = sizeof(struct iir_tf_5_config); + *param_id = ASM_PARAM_ID_IIRUNING_FILTER_CONFIG_PARAMS; + *module_id = ASM_MODULE_ID_IIRUNING_FILTER; + break; + + case AHC_MBDRC_REG_ENABLE: + pr_debug("%s: AHC_MBDRC_REG_ENABLE\n", __func__); + *param_len = sizeof(struct audproc_common_enable); + *param_id = AUDPROC_PARAM_ID_ENABLE; + *module_id = ASM_MODULE_ID_MBDRCV3; + break; + + case AHC_MBDRC_REG_ENABLE_CONFIG: + pr_debug("%s: AHC_MBDRC_REG_ENABLE_CONFIG\n", __func__); + *param_len = sizeof(struct asm_mbdrc_enable); + *param_id = ASM_PARAM_ID_MBDRC_ENABLE; + *module_id = ASM_MODULE_ID_MBDRCV3; + break; + + default: + pr_err("%s: Received unknown command %d\n", __func__, cmd); + *param_len = 0; + *param_id = 0; + *module_id = 0; + return -EINVAL; + } + return 0; +} + +static int set_values_for_get_cmd(int cmd, int band, + struct snd_ctl_elem_value *ucontrol, uint8_t *params_value) +{ + switch (cmd) { + case AHC_IIR_TF_REG_ENABLE: /* FALLTHROUGH */ + case AHC_MBDRC_REG_ENABLE: { + struct audproc_common_enable *param = + (struct audproc_common_enable *)params_value; + ucontrol->value.integer.value[0] = param->enable; + pr_debug("%s: Val %ld returned\n", __func__, + ucontrol->value.integer.value[0]); + break; + } + + case AHC_IIR_TF_REG_ENABLE_CONFIG: { + struct asm_iiruning_filter_enable *param = + (struct asm_iiruning_filter_enable *)params_value; + ucontrol->value.integer.value[0] = param->enable_flag; + pr_debug("%s: Val %ld returned\n", __func__, + ucontrol->value.integer.value[0]); + break; + } + + case AHC_IIR_TF_REG_PRE_GAIN: { + struct asm_iiruning_filter_pregain *param = + (struct asm_iiruning_filter_pregain *)params_value; + ucontrol->value.integer.value[0] = param->pregain; + pr_debug("%s: Val %ld returned\n", __func__, + ucontrol->value.integer.value[0]); + break; + } + + case AHC_IIR_TF_REG_CONFIG_PARAMS: { + struct iir_tf_5_config *param = + (struct iir_tf_5_config *)params_value; + int32_t *p_coeff; + int i; + + if (band < param->bands.num_biquad_stages) + p_coeff = ¶m->coeffs[band][0]; + else + p_coeff = &default_coeff[0]; + + for (i = 0; i < 5; i++) { + ucontrol->value.integer.value[i] = p_coeff[i]; + pr_debug("%s: Val %ld returned\n", __func__, + ucontrol->value.integer.value[i]); + } + break; + } + + case AHC_IIR_TF_REG_CONFIG_ALL_PARAMS: { + struct iir_tf_5_config *param = + (struct iir_tf_5_config *)params_value; + int32_t *p_coeff; + int i; + int j; + int idx = 0; + + for (i = 0; i < AHC_BANDS_USED; i++) { + if (i < param->bands.num_biquad_stages) + p_coeff = ¶m->coeffs[i][0]; + else + p_coeff = &default_coeff[0]; + + for (j = 0; j < 5; j++) { + ucontrol->value.integer.value[idx] = p_coeff[j]; + pr_debug("%s: Val %ld returned\n", __func__, + ucontrol->value.integer.value[i]); + idx++; + } + } + break; + } + + case AHC_MBDRC_REG_ENABLE_CONFIG: { + struct asm_mbdrc_enable *param = + (struct asm_mbdrc_enable *)params_value; + ucontrol->value.integer.value[0] = param->enable_flag; + pr_debug("%s: Val %ld returned\n", __func__, + ucontrol->value.integer.value[0]); + break; + } + + default: + /* Will never happen. Checked in get_params_for_get_cmd */ + break; + } + return 0; +} + +static int handle_get_cmd(int cmd, int band, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + int param_len = 0; + uint32_t param_id = 0; + uint32_t module_id = 0; + uint8_t *params_value; + + if ((ahc_copp_idx < 0) || (ahc_copp_idx > MAX_COPPS_PER_PORT)) { + pr_err("%s: ahc_copp_idx not set\n", __func__); + return -EINVAL; + } + + rc = get_params_for_get_cmd(cmd, band, ¶m_len, ¶m_id, + &module_id); + if (rc) + return rc; + + /* Adjust size to 4-byte alignment. */ + param_len = (param_len + 3) & ~3; + + params_value = kzalloc(param_len + sizeof(struct adm_param_data_v5), GFP_KERNEL); + if (!params_value) { + pr_err("%s: params memory alloc failed\n", __func__); + return -ENOMEM; + } + + pr_debug("%s: Retrieving parameters len %d\n", __func__, param_len); + /* + * Retrieve the parameters. + * param_len must be increased with size of struct adm_param_data_v5 + * because adm_get_params() does not add this size to the return + * buffer allocation even though that header is always included + * before the actual parameter payload. + */ + rc = adm_get_params(AHC_PORT_ID, + ahc_copp_idx, + module_id, + param_id, + param_len + sizeof(struct adm_param_data_v5), + params_value); + if (rc) { + pr_err("%s: get parameters failed %d\n", __func__, rc); + goto exit; + } + + rc = set_values_for_get_cmd(cmd, band, ucontrol, params_value); + +exit: + kfree(params_value); + return rc; +} + +static int handle_put_cmd(int cmd, int band, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + if ((ahc_copp_idx < 0) || (ahc_copp_idx > MAX_COPPS_PER_PORT)) { + pr_err("%s: ahc_copp_idx not set\n", __func__); + return -EINVAL; + } + + switch (cmd) { + case AHC_IIR_TF_REG_ENABLE: { + struct audproc_common_enable param; + + param.enable = ucontrol->value.integer.value[0]; + pr_debug("%s: AHC_IIR_TF_REG_ENABLE val: %u\n", + __func__, param.enable); + rc = iir_tf_send_params(AHC_PORT_ID, + ASM_MODULE_ID_IIRUNING_FILTER, + AUDPROC_PARAM_ID_ENABLE, + (uint8_t *)¶m, sizeof(param)); + break; + } + + case AHC_IIR_TF_REG_ENABLE_CONFIG: { + struct asm_iiruning_filter_enable param; + + param.enable_flag = ucontrol->value.integer.value[0]; + pr_debug("%s: AHC_IIR_TF_REG_ENABLE_CONFIG val: %u\n", + __func__, param.enable_flag); + rc = iir_tf_send_params(AHC_PORT_ID, + ASM_MODULE_ID_IIRUNING_FILTER, + ASM_PARAM_ID_IIRUNING_FILTER_ENABLE_CONFIG, + (uint8_t *)¶m, sizeof(param)); + break; + } + + case AHC_IIR_TF_REG_PRE_GAIN: { + struct asm_iiruning_filter_pregain param; + + pr_debug("%s: AHC_IIR_TF_REG_PRE_GAIN val: %ld\n", + __func__, ucontrol->value.integer.value[0]); + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > 0xFFFF) { + pr_err("%s: value %ld is not uint16_t", __func__, + ucontrol->value.integer.value[0]); + return -EINVAL; + } + param.pregain = ucontrol->value.integer.value[0]; + param.reserved = 0; + rc = iir_tf_send_params(AHC_PORT_ID, + ASM_MODULE_ID_IIRUNING_FILTER, + ASM_PARAM_ID_IIRUNING_FILTER_PRE_GAIN, + (uint8_t *)¶m, sizeof(param)); + break; + } + + case AHC_IIR_TF_REG_CONFIG_PARAMS: { + long *temp = ucontrol->value.integer.value; + int i; + + /* Two prints to avoid checkpatch warning */ + pr_debug("%s: AHC_IIR_TF_REG_CONFIG_PARAMS band %d:", + __func__, band); + pr_debug(" %ld %ld %ld %ld %ld\n", + temp[0], temp[1], temp[2], temp[3], temp[4]); + + for (i = 0; i < 5; i++) + iir_tf_coeffs[band].coeff[i] = temp[i]; + + rc = send_iir_config(); + break; + } + + case AHC_IIR_TF_REG_CONFIG_ALL_PARAMS: { + long *temp = ucontrol->value.integer.value; + int i; + int j; + + pr_debug("%s: AHC_IIR_TF_REG_CONFIG_ALL_PARAMS", __func__); + + for (i = 0; i < AHC_BANDS_USED; i++) + for (j = 0; j < 5; j++) + iir_tf_coeffs[i].coeff[j] = + temp[(i * 5) + j]; + + rc = send_iir_config(); + break; + } + + case AHC_MBDRC_REG_ENABLE: { + struct audproc_common_enable param; + + param.enable = ucontrol->value.integer.value[0]; + pr_debug("%s: AHC_MBDRC_REG_ENABLE recvd val: %u\n", + __func__, param.enable); + rc = iir_tf_send_params(AHC_PORT_ID, ASM_MODULE_ID_MBDRCV3, + AUDPROC_PARAM_ID_ENABLE, + (uint8_t *)¶m, sizeof(param)); + break; + } + + case AHC_MBDRC_REG_ENABLE_CONFIG: { + struct asm_mbdrc_enable param; + + param.enable_flag = ucontrol->value.integer.value[0]; + pr_debug("%s: AHC_MBDRC_REG_ENABLE_CONFIG recvd val: %u\n", + __func__, param.enable_flag); + rc = iir_tf_send_params(AHC_PORT_ID, ASM_MODULE_ID_MBDRCV3, + ASM_PARAM_ID_MBDRC_ENABLE, + (uint8_t *)¶m, sizeof(param)); + break; + } + + default: + pr_err("%s: Received unknown command %d\n", __func__, cmd); + rc = -EINVAL; + break; + } + + return rc; +} + +static int get_ahc_multi_param( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct soc_multi_mixer_control *mc = + (struct soc_multi_mixer_control *) + kcontrol->private_value; + + return handle_get_cmd(mc->reg, mc->shift, ucontrol); +} + +static int put_ahc_multi_param( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct soc_multi_mixer_control *mc = + (struct soc_multi_mixer_control *) + kcontrol->private_value; + + return handle_put_cmd(mc->reg, mc->shift, ucontrol); +} + +static const struct snd_kcontrol_new ahc_multi_controls[] = { + + /* IIR Tuning Filter */ + SOC_SINGLE_MULTI_EXT("AHC IIR Enable", AHC_IIR_TF_REG_ENABLE, + 0, 1, 0, 1, + get_ahc_multi_param, put_ahc_multi_param), + + SOC_SINGLE_MULTI_EXT("AHC IIR EnableConfig", + AHC_IIR_TF_REG_ENABLE_CONFIG, + 0, 1, 0, 1, + get_ahc_multi_param, put_ahc_multi_param), + + SOC_SINGLE_MULTI_EXT("AHC IIR PreGain", AHC_IIR_TF_REG_PRE_GAIN, + 0, 0x0000FFFF, 0, 1, + get_ahc_multi_param, put_ahc_multi_param), + + SOC_SINGLE_MULTI_EXT("AHC IIR Band1", AHC_IIR_TF_REG_CONFIG_PARAMS, + AHC_IIR_TF_SHIFT_BAND1, 0xFFFFFFFF, 0, 5, + get_ahc_multi_param, put_ahc_multi_param), + + SOC_SINGLE_MULTI_EXT("AHC IIR Band2", AHC_IIR_TF_REG_CONFIG_PARAMS, + AHC_IIR_TF_SHIFT_BAND2, 0xFFFFFFFF, 0, 5, + get_ahc_multi_param, put_ahc_multi_param), + + SOC_SINGLE_MULTI_EXT("AHC IIR Band3", AHC_IIR_TF_REG_CONFIG_PARAMS, + AHC_IIR_TF_SHIFT_BAND3, 0xFFFFFFFF, 0, 5, + get_ahc_multi_param, put_ahc_multi_param), + + SOC_SINGLE_MULTI_EXT("AHC IIR Band4", AHC_IIR_TF_REG_CONFIG_PARAMS, + AHC_IIR_TF_SHIFT_BAND4, 0xFFFFFFFF, 0, 5, + get_ahc_multi_param, put_ahc_multi_param), + + SOC_SINGLE_MULTI_EXT("AHC IIR Band5", AHC_IIR_TF_REG_CONFIG_PARAMS, + AHC_IIR_TF_SHIFT_BAND5, 0xFFFFFFFF, 0, 5, + get_ahc_multi_param, put_ahc_multi_param), + + SOC_SINGLE_MULTI_EXT("AHC IIR Bands", AHC_IIR_TF_REG_CONFIG_ALL_PARAMS, + 0, 0xFFFFFFFF, 0, 25, + get_ahc_multi_param, put_ahc_multi_param), + + /* MBDRC */ + SOC_SINGLE_MULTI_EXT("AHC MBDRC Enable", AHC_MBDRC_REG_ENABLE, + 0, 1, 0, 1, + get_ahc_multi_param, put_ahc_multi_param), + + SOC_SINGLE_MULTI_EXT("AHC MBDRC EnableConfig", + AHC_MBDRC_REG_ENABLE_CONFIG, + 0, 1, 0, 1, + get_ahc_multi_param, put_ahc_multi_param), +}; + +void msm_routing_ahc_set_copp_idx(int copp_idx) +{ + pr_debug("%s: copp_idx %d\n", __func__, copp_idx); + ahc_copp_idx = copp_idx; +} + +void msm_routing_ahc_add_controls(struct snd_soc_platform *platform) +{ + int rc; + + rc = snd_soc_add_platform_controls(platform, ahc_multi_controls, + ARRAY_SIZE(ahc_multi_controls)); + if (rc) + pr_err("%s: Failed to add multi controls %d\n", __func__, rc); +} diff --git a/sound/soc/msm/qdsp6v2/msm-ahc-config.h b/sound/soc/msm/qdsp6v2/msm-ahc-config.h new file mode 100644 index 0000000000000000000000000000000000000000..c732acc08db609d99bb9b8ad16b08894dc69453b --- /dev/null +++ b/sound/soc/msm/qdsp6v2/msm-ahc-config.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#ifndef _MSM_AHC_CONFIG_H_ +#define _MSM_AHC_CONFIG_H_ + +#define AHC_PORT_ID SLIMBUS_0_RX + +#ifdef CONFIG_AHC +void msm_routing_ahc_set_copp_idx(int copp_idx); +void msm_routing_ahc_add_controls(struct snd_soc_platform *platform); +#else +void msm_routing_ahc_set_copp_idx(int copp_idx) {} +void msm_routing_ahc_add_controls(struct snd_soc_platform *platform) {} +#endif + +#endif diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c index 1286d318578020e8c2418a3eed07ebd708c5a216..e312a879b86a5a7f7727374a2787f338555d32f0 100644 --- a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c @@ -155,7 +155,7 @@ int msm_audio_effects_virtualizer_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "VIRT ENABLE", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER; *updt_params++ = @@ -183,7 +183,7 @@ int msm_audio_effects_virtualizer_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "VIRT STRENGTH", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER; *updt_params++ = @@ -211,7 +211,7 @@ int msm_audio_effects_virtualizer_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "VIRT OUT_TYPE", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER; *updt_params++ = @@ -239,7 +239,7 @@ int msm_audio_effects_virtualizer_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "VIRT GAIN_ADJUST", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER; *updt_params++ = @@ -318,7 +318,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_ENABLE", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -346,7 +346,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_MODE", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -374,7 +374,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_PRESET", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -402,7 +402,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_WET_MIX", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -430,7 +430,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_GAIN_ADJUST", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -458,7 +458,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_ROOM_LEVEL", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -486,7 +486,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_ROOM_HF_LEVEL", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -514,7 +514,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_DECAY_TIME", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -542,7 +542,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_DECAY_HF_RATIO", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -570,7 +570,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_REFLECTIONS_LEVEL", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -598,7 +598,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_REFLECTIONS_DELAY", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -626,7 +626,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_LEVEL", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -654,7 +654,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_DELAY", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -682,7 +682,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_DIFFUSION", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -710,7 +710,7 @@ int msm_audio_effects_reverb_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "REVERB_DENSITY", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_REVERB; *updt_params++ = @@ -790,7 +790,7 @@ int msm_audio_effects_bass_boost_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "BASS_BOOST_ENABLE", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST; *updt_params++ = @@ -818,7 +818,7 @@ int msm_audio_effects_bass_boost_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "BASS_BOOST_MODE", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST; *updt_params++ = @@ -846,7 +846,7 @@ int msm_audio_effects_bass_boost_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "BASS_BOOST_STRENGTH", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST; *updt_params++ = @@ -924,7 +924,7 @@ int msm_audio_effects_pbe_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "PBE_ENABLE", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_PBE; *updt_params++ = @@ -950,7 +950,7 @@ int msm_audio_effects_pbe_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "PBE_PARAM", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_PBE; *updt_params++ = @@ -1035,7 +1035,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "EQ_ENABLE", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_POPLESS_EQUALIZER; *updt_params++ = @@ -1103,7 +1103,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "EQ_CONFIG", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_POPLESS_EQUALIZER; *updt_params++ = @@ -1154,7 +1154,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "EQ_BAND_INDEX", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_POPLESS_EQUALIZER; *updt_params++ = @@ -1186,7 +1186,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, MAX_INBAND_PARAM_SZ, "EQ_SINGLE_BAND_FREQ", rc); if (rc != 0) - goto invalid_config; + break; *updt_params++ = AUDPROC_MODULE_ID_POPLESS_EQUALIZER; *updt_params++ = @@ -1276,7 +1276,7 @@ static int __msm_audio_effects_volume_handler(struct audio_client *ac, "VOLUME/VOLUME2_GAIN_2CH", rc); if (rc != 0) - goto invalid_config; + break; if (instance == SOFT_VOLUME_INSTANCE_2) *updt_params++ = ASM_MODULE_ID_VOL_CTRL2; @@ -1325,7 +1325,7 @@ static int __msm_audio_effects_volume_handler(struct audio_client *ac, "VOLUME/VOLUME2_GAIN_MASTER", rc); if (rc != 0) - goto invalid_config; + break; if (instance == SOFT_VOLUME_INSTANCE_2) *updt_params++ = ASM_MODULE_ID_VOL_CTRL2; diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 4519d2a2b5a27786fb12177dcf24319a5d10bc16..993f7be90234933868d26c77eb67a3256ee72e74 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include @@ -39,13 +44,13 @@ #include #include -#include #include #include #include #include #include "msm-pcm-routing-v2.h" #include "msm-qti-pp-config.h" +#include "msm-sony-hweffect.h" #define DSP_PP_BUFFERING_IN_MSEC 25 #define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC 150 @@ -100,11 +105,11 @@ struct msm_compr_pdata { struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX]; uint32_t volume[MSM_FRONTEND_DAI_MAX][2]; /* For both L & R */ struct msm_compr_audio_effects *audio_effects[MSM_FRONTEND_DAI_MAX]; + struct msm_compr_sony_hweffect *sony_hweffect[MSM_FRONTEND_DAI_MAX]; bool use_dsp_gapless_mode; bool use_legacy_api; /* indicates use older asm apis*/ struct msm_compr_dec_params *dec_params[MSM_FRONTEND_DAI_MAX]; struct msm_compr_ch_map *ch_map[MSM_FRONTEND_DAI_MAX]; - int32_t ion_fd[MSM_FRONTEND_DAI_MAX]; }; struct msm_compr_audio { @@ -158,12 +163,6 @@ struct msm_compr_audio { uint32_t start_delay_lsw; uint32_t start_delay_msw; - int32_t shm_ion_fd; - struct ion_client *lib_ion_client; - struct ion_client *shm_ion_client; - struct ion_handle *lib_ion_handle; - struct ion_handle *shm_ion_handle; - uint64_t marker_timestamp; struct msm_compr_gapless_state gapless_state; @@ -206,6 +205,10 @@ struct msm_compr_audio_effects { struct query_audio_effect query; }; +struct msm_compr_sony_hweffect { + struct sonybundle_params sonybundle; +}; + struct msm_compr_dec_params { struct snd_dec_ddp ddp_params; }; @@ -1273,9 +1276,6 @@ static int msm_compr_configure_dsp_for_playback int dir = IN, ret = 0; struct audio_client *ac = prtd->audio_client; uint32_t stream_index; - union snd_codec_options *codec_options = - &(prtd->codec_param.codec.options); - struct asm_softpause_params softpause = { .enable = SOFT_PAUSE_ENABLE, .period = SOFT_PAUSE_PERIOD, @@ -1300,9 +1300,6 @@ static int msm_compr_configure_dsp_for_playback bits_per_sample = 24; else if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S32_LE) bits_per_sample = 32; - else if (prtd->codec == FORMAT_FLAC && codec_options && - (codec_options->flac_dec.sample_size != 0)) - bits_per_sample = codec_options->flac_dec.sample_size; if (prtd->compr_passthr != LEGACY_PCM) { ret = q6asm_open_write_compressed(ac, prtd->codec, @@ -1520,65 +1517,6 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) return ret; } -static int msm_compr_map_ion_fd(struct msm_compr_audio *prtd, int fd) -{ - ion_phys_addr_t paddr; - size_t pa_len = 0; - int ret = 0; - - ret = msm_audio_ion_phys_assign("audio_lib_mem_client", - &prtd->lib_ion_client, - &prtd->lib_ion_handle, - fd, &paddr, &pa_len, HLOS_TO_ADSP); - if (ret) { - pr_err("%s: audio lib ION phys failed, rc = %d\n", - __func__, ret); - goto done; - } - - ret = q6core_add_remove_pool_pages(paddr, pa_len, - ADSP_MEMORY_MAP_HLOS_PHYSPOOL, true); - if (ret) { - pr_err("%s: add remove pages failed, rc = %d\n", __func__, ret); - /* Assign back to HLOS if add pages cmd failed */ - msm_audio_ion_phys_free(prtd->lib_ion_client, - prtd->lib_ion_handle, - &paddr, &pa_len, ADSP_TO_HLOS); - } - -done: - return ret; -} - -static int msm_compr_unmap_ion_fd(struct msm_compr_audio *prtd) -{ - ion_phys_addr_t paddr; - size_t pa_len = 0; - int ret = 0; - - if (!prtd->lib_ion_client || !prtd->lib_ion_handle) { - pr_err("%s: ion_client or ion_handle is NULL", __func__); - return -EINVAL; - } - - ret = msm_audio_ion_phys_free(prtd->lib_ion_client, - prtd->lib_ion_handle, - &paddr, &pa_len, ADSP_TO_HLOS); - if (ret) { - pr_err("%s: audio lib ION phys failed, rc = %d\n", - __func__, ret); - goto done; - } - - ret = q6core_add_remove_pool_pages(paddr, pa_len, - ADSP_MEMORY_MAP_HLOS_PHYSPOOL, false); - if (ret) - pr_err("%s: add remove pages failed, rc = %d\n", __func__, ret); - -done: - return ret; -} - static int msm_compr_playback_open(struct snd_compr_stream *cstream) { struct snd_compr_runtime *runtime = cstream->runtime; @@ -1586,7 +1524,6 @@ static int msm_compr_playback_open(struct snd_compr_stream *cstream) struct msm_compr_audio *prtd; struct msm_compr_pdata *pdata = snd_soc_platform_get_drvdata(rtd->platform); - int ret = 0; pr_debug("%s\n", __func__); prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL); @@ -1602,16 +1539,33 @@ static int msm_compr_playback_open(struct snd_compr_stream *cstream) kzalloc(sizeof(struct msm_compr_audio_effects), GFP_KERNEL); if (!pdata->audio_effects[rtd->dai_link->be_id]) { pr_err("%s: Could not allocate memory for effects\n", __func__); - ret = -ENOMEM; - goto effect_err; + pdata->cstream[rtd->dai_link->be_id] = NULL; + kfree(prtd); + return -ENOMEM; + } + pdata->sony_hweffect[rtd->dai_link->be_id] = + kzalloc(sizeof(struct msm_compr_sony_hweffect), GFP_KERNEL); + if (!pdata->sony_hweffect[rtd->dai_link->be_id]) { + pr_err("%s: Could not allocate memory for effects\n", __func__); + kfree(pdata->audio_effects[rtd->dai_link->be_id]); + pdata->cstream[rtd->dai_link->be_id] = NULL; + kfree(prtd); + return -ENOMEM; } + + init_sonybundle_params( + &(pdata->sony_hweffect[rtd->dai_link->be_id]->sonybundle)); + pdata->dec_params[rtd->dai_link->be_id] = kzalloc(sizeof(struct msm_compr_dec_params), GFP_KERNEL); if (!pdata->dec_params[rtd->dai_link->be_id]) { pr_err("%s: Could not allocate memory for dec params\n", __func__); - ret = -ENOMEM; - goto param_err; + kfree(pdata->audio_effects[rtd->dai_link->be_id]); + kfree(pdata->sony_hweffect[rtd->dai_link->be_id]); + pdata->cstream[rtd->dai_link->be_id] = NULL; + kfree(prtd); + return -ENOMEM; } prtd->codec = FORMAT_MP3; prtd->bytes_received = 0; @@ -1655,32 +1609,19 @@ static int msm_compr_playback_open(struct snd_compr_stream *cstream) (app_cb)compr_event_handler, prtd); if (!prtd->audio_client) { pr_err("%s: Could not allocate memory for client\n", __func__); - ret = -ENOMEM; - goto ac_err; + kfree(pdata->audio_effects[rtd->dai_link->be_id]); + kfree(pdata->dec_params[rtd->dai_link->be_id]); + pdata->cstream[rtd->dai_link->be_id] = NULL; + runtime->private_data = NULL; + kfree(prtd); + return -ENOMEM; } pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session); prtd->audio_client->perf_mode = false; prtd->session_id = prtd->audio_client->session; msm_adsp_init_mixer_ctl_pp_event_queue(rtd); - if (pdata->ion_fd[rtd->dai_link->be_id] > 0) { - ret = msm_compr_map_ion_fd(prtd, - pdata->ion_fd[rtd->dai_link->be_id]); - if (ret < 0) - goto map_err; - } - return 0; -map_err: - q6asm_audio_client_free(prtd->audio_client); -ac_err: - kfree(pdata->dec_params[rtd->dai_link->be_id]); -param_err: - kfree(pdata->audio_effects[rtd->dai_link->be_id]); -effect_err: - pdata->cstream[rtd->dai_link->be_id] = NULL; - runtime->private_data = NULL; - kfree(prtd); - return ret; + return 0; } static int msm_compr_capture_open(struct snd_compr_stream *cstream) @@ -1759,8 +1700,6 @@ static int msm_compr_playback_free(struct snd_compr_stream *cstream) int dir = IN, ret = 0, stream_id; unsigned long flags; uint32_t stream_index; - ion_phys_addr_t paddr; - size_t pa_len = 0; pr_debug("%s\n", __func__); @@ -1834,19 +1773,13 @@ static int msm_compr_playback_free(struct snd_compr_stream *cstream) } q6asm_audio_client_buf_free_contiguous(dir, ac); - if (prtd->shm_ion_fd > 0) - msm_audio_ion_phys_free(prtd->shm_ion_client, - prtd->shm_ion_handle, - &paddr, &pa_len, ADSP_TO_HLOS); - if (pdata->ion_fd[soc_prtd->dai_link->be_id] > 0) { - msm_compr_unmap_ion_fd(prtd); - pdata->ion_fd[soc_prtd->dai_link->be_id] = 0; - } q6asm_audio_client_free(ac); msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd); kfree(pdata->audio_effects[soc_prtd->dai_link->be_id]); pdata->audio_effects[soc_prtd->dai_link->be_id] = NULL; + kfree(pdata->sony_hweffect[soc_prtd->dai_link->be_id]); + pdata->sony_hweffect[soc_prtd->dai_link->be_id] = NULL; kfree(pdata->dec_params[soc_prtd->dai_link->be_id]); pdata->dec_params[soc_prtd->dai_link->be_id] = NULL; kfree(prtd); @@ -2204,8 +2137,6 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) int stream_id; uint32_t stream_index; uint16_t bits_per_sample = 16; - union snd_codec_options *codec_options = - &(prtd->codec_param.codec.options); spin_lock_irqsave(&prtd->lock, flags); if (atomic_read(&prtd->error)) { @@ -2624,9 +2555,6 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) else if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S32_LE) bits_per_sample = 32; - else if (prtd->codec == FORMAT_FLAC && codec_options && - (codec_options->flac_dec.sample_size != 0)) - bits_per_sample = codec_options->flac_dec.sample_size; pr_debug("%s: open_write stream_id %d bits_per_sample %d", __func__, stream_id, bits_per_sample); @@ -3309,6 +3237,71 @@ static int msm_compr_audio_effects_config_get(struct snd_kcontrol *kcontrol, return 0; } +static int msm_compr_sony_hweffect_config_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) + snd_soc_component_get_drvdata(comp); + struct msm_compr_sony_hweffect *sony_hweffect = NULL; + struct snd_compr_stream *cstream = NULL; + struct msm_compr_audio *prtd = NULL; + long *values = &(ucontrol->value.integer.value[0]); + int effects_module; + uint16_t bits_per_sample; + + pr_debug("%s\n", __func__); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds fe_id %lu\n", + __func__, fe_id); + return -EINVAL; + } + cstream = pdata->cstream[fe_id]; + sony_hweffect = pdata->sony_hweffect[fe_id]; + if (!cstream || !sony_hweffect) { + pr_err("%s: stream or effects inactive\n", __func__); + return -EINVAL; + } + prtd = cstream->runtime->private_data; + if (!prtd) { + pr_err("%s: cannot set audio effects\n", __func__); + return -EINVAL; + } + effects_module = *values++; + switch (effects_module) { + case SONYBUNDLE_MODULE: + pr_debug("%s: SONYBUNDLE_MODULE\n", __func__); + + if ((prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE) || + (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_3LE)) + bits_per_sample = 24; + else if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S32_LE) + bits_per_sample = 32; + else + bits_per_sample = 16; + + msm_sony_hweffect_sonybundle_handler(prtd->audio_client, + &(sony_hweffect->sonybundle), + values, + prtd->sample_rate, + bits_per_sample, + prtd->num_channels); + break; + default: + pr_err("%s Invalid effects config module\n", __func__); + return -EINVAL; + } + return 0; +} + +static int msm_compr_sony_hweffect_config_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* dummy function */ + return 0; +} + static int msm_compr_query_audio_effect_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3754,120 +3747,7 @@ done: return ret; } -static int msm_compr_playback_dnmix_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret = 0; - int len = 0; - int i = 0; - struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); - unsigned long fe_id = kcontrol->private_value; - struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) - snd_soc_component_get_drvdata(comp); - struct snd_compr_stream *cstream = NULL; - struct msm_compr_audio *prtd; - struct asm_stream_pan_ctrl_params dnmix_param; - int be_id = ucontrol->value.integer.value[len++]; - int stream_id = 0; - /* - * Max index for this mixer control includes below - * be_id (1) - * num_output_channels (1) - * num_input_channels (1) - * output ch map (max) (8) - * input ch map (max) (8) - * mix matrix coefficients (max)(64) - */ - int max_index = 0; - int max_mixer_ctrl_value_size = 128; - - if (fe_id >= MSM_FRONTEND_DAI_MAX) { - pr_err("%s Received out of bounds invalid fe_id %lu\n", - __func__, fe_id); - ret = -EINVAL; - goto done; - } - - cstream = pdata->cstream[fe_id]; - if (cstream == NULL) { - pr_err("%s cstream is null\n", __func__); - ret = -EINVAL; - goto done; - } - - prtd = cstream->runtime->private_data; - if (!prtd) { - pr_err("%s: prtd is null\n", __func__); - ret = -EINVAL; - goto done; - } - - if (prtd->audio_client == NULL) { - pr_err("%s: audio_client is null\n", __func__); - ret = -EINVAL; - goto done; - } - - stream_id = prtd->audio_client->session; - if (len >= max_mixer_ctrl_value_size) { - ret = -EINVAL; - goto done; - } - dnmix_param.num_output_channels = - ucontrol->value.integer.value[len++]; - if (dnmix_param.num_output_channels > - PCM_FORMAT_MAX_NUM_CHANNEL) { - ret = -EINVAL; - goto done; - } - if (len >= max_mixer_ctrl_value_size) { - ret = -EINVAL; - goto done; - } - dnmix_param.num_input_channels = - ucontrol->value.integer.value[len++]; - if (dnmix_param.num_input_channels > - PCM_FORMAT_MAX_NUM_CHANNEL) { - ret = -EINVAL; - goto done; - } - max_index = len + dnmix_param.num_output_channels + - dnmix_param.num_input_channels + - dnmix_param.num_output_channels * - dnmix_param.num_input_channels; - if (max_index >= max_mixer_ctrl_value_size) { - ret = -EINVAL; - goto done; - } - - if (ucontrol->value.integer.value[len++]) { - for (i = 0; i < dnmix_param.num_output_channels; i++) { - dnmix_param.output_channel_map[i] = - ucontrol->value.integer.value[len++]; - } - } - if (ucontrol->value.integer.value[len++]) { - for (i = 0; i < dnmix_param.num_input_channels; i++) { - dnmix_param.input_channel_map[i] = - ucontrol->value.integer.value[len++]; - } - } - if (ucontrol->value.integer.value[len++]) { - for (i = 0; i < dnmix_param.num_output_channels * - dnmix_param.num_input_channels; i++) { - dnmix_param.gain[i] = - ucontrol->value.integer.value[len++]; - } - } - msm_routing_set_downmix_control_data(be_id, - stream_id, - &dnmix_param); - -done: - return ret; -} - -static int msm_compr_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol, +static int msm_compr_ion_fd_map_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); @@ -3876,6 +3756,7 @@ static int msm_compr_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol, snd_soc_component_get_drvdata(comp); struct snd_compr_stream *cstream = NULL; struct msm_compr_audio *prtd; + int fd; int ret = 0; if (fe_id >= MSM_FRONTEND_DAI_MAX) { @@ -3905,36 +3786,10 @@ static int msm_compr_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol, goto done; } - memcpy(&prtd->shm_ion_fd, ucontrol->value.bytes.data, - sizeof(prtd->shm_ion_fd)); - ret = q6asm_audio_map_shm_fd(prtd->audio_client, - &prtd->shm_ion_client, - &prtd->shm_ion_handle, prtd->shm_ion_fd); + memcpy(&fd, ucontrol->value.bytes.data, sizeof(fd)); + ret = q6asm_send_ion_fd(prtd->audio_client, fd); if (ret < 0) - pr_err("%s: failed to map shm mem\n", __func__); -done: - return ret; -} - -static int msm_compr_lib_ion_fd_map_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); - unsigned long fe_id = kcontrol->private_value; - struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) - snd_soc_component_get_drvdata(comp); - int ret = 0; - - if (fe_id >= MSM_FRONTEND_DAI_MAX) { - pr_err("%s Received out of bounds invalid fe_id %lu\n", - __func__, fe_id); - ret = -EINVAL; - goto done; - } - - memcpy(&pdata->ion_fd[fe_id], ucontrol->value.bytes.data, - sizeof(pdata->ion_fd[fe_id])); - + pr_err("%s: failed to register ion fd\n", __func__); done: return ret; } @@ -4049,6 +3904,7 @@ static int msm_compr_probe(struct snd_soc_platform *platform) pdata->volume[i][0] = COMPRESSED_LR_VOL_MAX_STEPS; pdata->volume[i][1] = COMPRESSED_LR_VOL_MAX_STEPS; pdata->audio_effects[i] = NULL; + pdata->sony_hweffect[i] = NULL; pdata->dec_params[i] = NULL; pdata->cstream[i] = NULL; pdata->ch_map[i] = NULL; @@ -4138,16 +3994,6 @@ static int msm_compr_channel_map_info(struct snd_kcontrol *kcontrol, return 0; } -static int msm_compr_device_downmix_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 128; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 0xFFFFFFFF; - return 0; -} - static int msm_compr_add_volume_control(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Compress Playback"; @@ -4242,6 +4088,51 @@ static int msm_compr_add_audio_effects_control(struct snd_soc_pcm_runtime *rtd) return 0; } +static int msm_compr_add_sony_hweffect_control(struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = "Sony Audio Effects Config"; + char *mixer_str = NULL; + int ctl_len = 64; + struct snd_kcontrol_new fe_sony_hweffect_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_compr_audio_effects_config_info, + .get = msm_compr_sony_hweffect_config_get, + .put = msm_compr_sony_hweffect_config_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + return 0; + } + + pr_debug("%s: added new compr FE with name %s, id %d, cpu dai %s, device no %d\n", + __func__, rtd->dai_link->name, rtd->dai_link->be_id, + rtd->dai_link->cpu_dai_name, rtd->pcm->device); + + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + + if (!mixer_str) { + pr_err("failed to allocate mixer ctrl str of len %d", ctl_len); + return 0; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + + fe_sony_hweffect_config_control[0].name = mixer_str; + fe_sony_hweffect_config_control[0].private_value = rtd->dai_link->be_id; + pr_debug("Registering new mixer ctl %s\n", mixer_str); + snd_soc_add_platform_controls(rtd->platform, + fe_sony_hweffect_config_control, + ARRAY_SIZE(fe_sony_hweffect_config_control)); + kfree(mixer_str); + return 0; +} + static int msm_compr_add_query_audio_effect_control( struct snd_soc_pcm_runtime *rtd) { @@ -4446,53 +4337,6 @@ static int msm_compr_add_dec_runtime_params_control( return 0; } -static int msm_compr_add_device_down_mix_controls( - struct snd_soc_pcm_runtime *rtd) -{ - const char *playback_mixer_ctl_name = "Audio Device"; - const char *deviceNo = "NN"; - const char *suffix = "Downmix Control"; - char *mixer_str = NULL; - int ctl_len = 0, ret = 0; - struct snd_kcontrol_new device_downmix_control[1] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "?", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = msm_compr_device_downmix_info, - .put = msm_compr_playback_dnmix_ctl_put, - .private_value = 0, - } - }; - - if (!rtd) { - pr_err("%s NULL rtd\n", __func__); - ret = -EINVAL; - goto done; - } - ctl_len = strlen(playback_mixer_ctl_name) + 1 + - strlen(deviceNo) + 1 + strlen(suffix) + 1; - mixer_str = kzalloc(ctl_len, GFP_KERNEL); - if (!mixer_str) { - ret = -ENOMEM; - goto done; - } - - snprintf(mixer_str, ctl_len, "%s %d %s", - playback_mixer_ctl_name, rtd->pcm->device, suffix); - device_downmix_control[0].name = mixer_str; - device_downmix_control[0].private_value = rtd->dai_link->be_id; - ret = snd_soc_add_platform_controls(rtd->platform, - device_downmix_control, - ARRAY_SIZE(device_downmix_control)); - if (ret < 0) - pr_err("%s: failed to add ctl %s\n", __func__, mixer_str); - - kfree(mixer_str); -done: - return ret; -} - static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd) { const char *playback_mixer_ctl_name = "Audio Stream"; @@ -4623,7 +4467,7 @@ static int msm_compr_add_channel_map_control(struct snd_soc_pcm_runtime *rtd) return 0; } -static int msm_compr_add_shm_ion_fd_cmd_control(struct snd_soc_pcm_runtime *rtd) +static int msm_compr_add_io_fd_cmd_control(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Playback ION FD"; const char *deviceNo = "NN"; @@ -4635,52 +4479,7 @@ static int msm_compr_add_shm_ion_fd_cmd_control(struct snd_soc_pcm_runtime *rtd) .name = "?", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_adsp_stream_cmd_info, - .put = msm_compr_shm_ion_fd_map_put, - .private_value = 0, - } - }; - - if (!rtd) { - pr_err("%s NULL rtd\n", __func__); - ret = -EINVAL; - goto done; - } - - ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; - mixer_str = kzalloc(ctl_len, GFP_KERNEL); - if (!mixer_str) { - ret = -ENOMEM; - goto done; - } - - snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); - fe_ion_fd_config_control[0].name = mixer_str; - fe_ion_fd_config_control[0].private_value = rtd->dai_link->be_id; - pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); - ret = snd_soc_add_platform_controls(rtd->platform, - fe_ion_fd_config_control, - ARRAY_SIZE(fe_ion_fd_config_control)); - if (ret < 0) - pr_err("%s: failed to add ctl %s\n", __func__, mixer_str); - - kfree(mixer_str); -done: - return ret; -} - -static int msm_compr_add_lib_ion_fd_cmd_control(struct snd_soc_pcm_runtime *rtd) -{ - const char *mixer_ctl_name = "Playback ION LIB FD"; - const char *deviceNo = "NN"; - char *mixer_str = NULL; - int ctl_len = 0, ret = 0; - struct snd_kcontrol_new fe_ion_fd_config_control[1] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "?", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = msm_adsp_stream_cmd_info, - .put = msm_compr_lib_ion_fd_map_put, + .put = msm_compr_ion_fd_map_put, .private_value = 0, } }; @@ -4781,29 +4580,24 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add Compr ADSP Stream Callback Control\n", __func__); - rc = msm_compr_add_shm_ion_fd_cmd_control(rtd); + rc = msm_compr_add_io_fd_cmd_control(rtd); if (rc) pr_err("%s: Could not add Compr ion fd Control\n", __func__); - rc = msm_compr_add_lib_ion_fd_cmd_control(rtd); - if (rc) - pr_err("%s: Could not add Compr ion lib fd Control\n", - __func__); - rc = msm_compr_add_event_ack_cmd_control(rtd); if (rc) pr_err("%s: Could not add Compr event ack Control\n", __func__); - rc = msm_compr_add_device_down_mix_controls(rtd); + rc = msm_compr_add_query_audio_effect_control(rtd); if (rc) - pr_err("%s: Could not add Compr downmix Control\n", + pr_err("%s: Could not add Compr Query Audio Effect Control\n", __func__); - rc = msm_compr_add_query_audio_effect_control(rtd); + rc = msm_compr_add_sony_hweffect_control(rtd); if (rc) - pr_err("%s: Could not add Compr Query Audio Effect Control\n", + pr_err("%s: Could not add Compr Sony H/W Effects Control\n", __func__); rc = msm_compr_add_dec_runtime_params_control(rtd); diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 292b3d04f7d51cec9d3157973cf5e23f6da8a919..fa8bdddacef2f7b01aaaf38d84c8bd0ee03d742f 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -4152,8 +4152,7 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, .rate_min = 8000, @@ -5148,27 +5147,6 @@ static int msm_dai_tdm_q6_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Clk Rate from DT file %d\n", __func__, tdm_clk_set.clk_freq_in_hz); - /* initialize static tdm clk attribute to default value */ - tdm_clk_set.clk_attri = Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO; - - /* extract tdm clk attribute into static */ - if (of_find_property(pdev->dev.of_node, - "qcom,msm-cpudai-tdm-clk-attribute", NULL)) { - rc = of_property_read_u16(pdev->dev.of_node, - "qcom,msm-cpudai-tdm-clk-attribute", - &tdm_clk_set.clk_attri); - if (rc) { - dev_err(&pdev->dev, "%s: clk attribute from DT file %s\n", - __func__, "qcom,msm-cpudai-tdm-clk-attribute"); - goto rtn; - } - dev_dbg(&pdev->dev, "%s: clk attribute from DT file %d\n", - __func__, tdm_clk_set.clk_attri); - } else { - dev_dbg(&pdev->dev, "%s: No optional clk attribute found\n", - __func__); - } - /* extract tdm clk src master/slave info into static */ rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-cpudai-tdm-clk-internal", @@ -6248,41 +6226,6 @@ static int msm_dai_q6_tdm_set_tdm_slot(struct snd_soc_dai *dai, return rc; } -static int msm_dai_q6_tdm_set_sysclk(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir) -{ - struct msm_dai_q6_tdm_dai_data *dai_data = - dev_get_drvdata(dai->dev); - - switch (dai->id) { - case AFE_PORT_ID_PRIMARY_TDM_RX: - case AFE_PORT_ID_PRIMARY_TDM_RX_1: - case AFE_PORT_ID_PRIMARY_TDM_RX_2: - case AFE_PORT_ID_PRIMARY_TDM_RX_3: - case AFE_PORT_ID_PRIMARY_TDM_RX_4: - case AFE_PORT_ID_PRIMARY_TDM_RX_5: - case AFE_PORT_ID_PRIMARY_TDM_RX_6: - case AFE_PORT_ID_PRIMARY_TDM_RX_7: - case AFE_PORT_ID_PRIMARY_TDM_TX: - case AFE_PORT_ID_PRIMARY_TDM_TX_1: - case AFE_PORT_ID_PRIMARY_TDM_TX_2: - case AFE_PORT_ID_PRIMARY_TDM_TX_3: - case AFE_PORT_ID_PRIMARY_TDM_TX_4: - case AFE_PORT_ID_PRIMARY_TDM_TX_5: - case AFE_PORT_ID_PRIMARY_TDM_TX_6: - case AFE_PORT_ID_PRIMARY_TDM_TX_7: - dai_data->clk_set.clk_freq_in_hz = freq; - break; - default: - return 0; - } - - dev_dbg(dai->dev, "%s: dai id = 0x%x group clk_freq %d\n", - __func__, dai->id, freq); - return 0; -} - - static int msm_dai_q6_tdm_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, unsigned int *tx_slot, unsigned int rx_num, unsigned int *rx_slot) @@ -6710,7 +6653,6 @@ static struct snd_soc_dai_ops msm_dai_q6_tdm_ops = { .hw_params = msm_dai_q6_tdm_hw_params, .set_tdm_slot = msm_dai_q6_tdm_set_tdm_slot, .set_channel_map = msm_dai_q6_tdm_set_channel_map, - .set_sysclk = msm_dai_q6_tdm_set_sysclk, .shutdown = msm_dai_q6_tdm_shutdown, }; diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c index 4de712a10f961fb5a7fd6b629a6ee7034159777b..850a669df9dea4c493ed4af611c0ee372ed4476d 100644 --- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c +++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c @@ -8,6 +8,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -334,14 +339,10 @@ int qti_set_custom_stereo_on(int port_id, int copp_idx, pr_debug("%s: port 0x%x, copp_idx %d, is_custom_stereo_on %d\n", __func__, port_id, copp_idx, is_custom_stereo_on); if (is_custom_stereo_on) { - op_FL_ip_FL_weight = - Q14_GAIN_ZERO_POINT_FIVE; - op_FL_ip_FR_weight = - Q14_GAIN_ZERO_POINT_FIVE; - op_FR_ip_FL_weight = - Q14_GAIN_ZERO_POINT_FIVE; - op_FR_ip_FR_weight = - Q14_GAIN_ZERO_POINT_FIVE; + op_FL_ip_FL_weight = 0; + op_FL_ip_FR_weight = Q14_GAIN_UNITY; + op_FR_ip_FL_weight = Q14_GAIN_UNITY; + op_FR_ip_FR_weight = 0; } else { op_FL_ip_FL_weight = Q14_GAIN_UNITY; op_FL_ip_FR_weight = 0; diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c index 35270e3340ecbf322d4d67e77106169e163814a9..3e72aa130c18d375e2191efbc98732da67628610 100644 --- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c +++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c @@ -1683,7 +1683,7 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s REG_SND_MODEL failed err %d\n", __func__, err); - goto done; + return err; } break; case SNDRV_LSM_SET_PARAMS: { @@ -1855,15 +1855,13 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: Invalid params event_status_v3\n", __func__); - err = -EINVAL; - goto done; + return -EINVAL; } if (copy_from_user(&userarg, arg, sizeof(userarg))) { dev_err(rtd->dev, "%s: err copyuser event_status_v3\n", __func__); - err = -EFAULT; - goto done; + return -EFAULT; } if (userarg.payload_size > @@ -1871,8 +1869,7 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream, pr_err("%s: payload_size %d is invalid, max allowed = %d\n", __func__, userarg.payload_size, LISTEN_MAX_STATUS_PAYLOAD_SIZE); - err = -EINVAL; - goto done; + return -EINVAL; } size = sizeof(struct snd_lsm_event_status_v3) + @@ -1882,8 +1879,7 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: Allocation failed event status size %d\n", __func__, size); - err = -EFAULT; - goto done; + return -EFAULT; } user->payload_size = userarg.payload_size; err = msm_lsm_ioctl_shared(substream, cmd, user); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c index 27627025877159755e245f9f59d8884aa4f7fc4f..6b026bafa27698b7eaf7cf58ff39f1e852779629 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c @@ -30,12 +30,9 @@ #include #include #include -#include - #include #include #include -#include #include "msm-pcm-q6-v2.h" #include "msm-pcm-routing-v2.h" @@ -424,42 +421,6 @@ static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } - -static int msm_pcm_mmap_fd(struct snd_pcm_substream *substream, - struct snd_pcm_mmap_fd *mmap_fd) -{ - struct msm_audio *prtd; - struct audio_port_data *apd; - struct audio_buffer *ab; - int dir = -1; - - if (!substream->runtime) { - pr_err("%s substream runtime not found\n", __func__); - return -EFAULT; - } - - prtd = substream->runtime->private_data; - if (!prtd || !prtd->audio_client || !prtd->mmap_flag) { - pr_err("%s no audio client or not an mmap session\n", __func__); - return -EINVAL; - } - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = IN; - else - dir = OUT; - - apd = prtd->audio_client->port; - ab = &(apd[dir].buf[0]); - mmap_fd->fd = ion_share_dma_buf_fd(ab->client, ab->handle); - if (mmap_fd->fd >= 0) { - mmap_fd->dir = dir; - mmap_fd->actual_size = ab->actual_size; - mmap_fd->size = ab->size; - } - return mmap_fd->fd < 0 ? -EFAULT : 0; -} - static int msm_pcm_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { @@ -484,15 +445,6 @@ static int msm_pcm_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl(substream, cmd, arg); } -#ifdef CONFIG_COMPAT -static int msm_pcm_compat_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - /* we only handle RESET which is common for both modes */ - return msm_pcm_ioctl(substream, cmd, arg); -} -#endif - static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -1042,101 +994,6 @@ static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd) return 0; } -static int msm_pcm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int ret = 0; - struct snd_pcm *pcm = hw->private_data; - struct snd_pcm_mmap_fd __user *_mmap_fd = NULL; - struct snd_pcm_mmap_fd mmap_fd; - struct snd_pcm_substream *substream = NULL; - int32_t dir = -1; - - switch (cmd) { - case SNDRV_PCM_IOCTL_MMAP_DATA_FD: - _mmap_fd = (struct snd_pcm_mmap_fd __user *)arg; - if (get_user(dir, (int32_t __user *)&(_mmap_fd->dir))) { - pr_err("%s: error copying mmap_fd from user\n", - __func__); - ret = -EFAULT; - break; - } - if (dir != OUT && dir != IN) { - pr_err("%s invalid stream dir\n", __func__); - ret = -EINVAL; - break; - } - substream = pcm->streams[dir].substream; - if (!substream) { - pr_err("%s substream not found\n", __func__); - ret = -ENODEV; - break; - } - pr_debug("%s : %s MMAP Data fd\n", __func__, - dir == 0 ? "P" : "C"); - if (msm_pcm_mmap_fd(substream, &mmap_fd) < 0) { - pr_err("%s: error getting fd\n", - __func__); - ret = -EFAULT; - break; - } - if (put_user(mmap_fd.fd, &_mmap_fd->fd) || - put_user(mmap_fd.size, &_mmap_fd->size) || - put_user(mmap_fd.actual_size, &_mmap_fd->actual_size)) { - pr_err("%s: error copying fd\n", __func__); - return -EFAULT; - } - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -#ifdef CONFIG_COMPAT -static int msm_pcm_hwdep_compat_ioctl(struct snd_hwdep *hw, - struct file *file, - unsigned int cmd, - unsigned long arg) -{ - /* we only support mmap fd. Handling is common in both modes */ - return msm_pcm_hwdep_ioctl(hw, file, cmd, arg); -} -#else -static int msm_pcm_hwdep_compat_ioctl(struct snd_hwdep *hw, - struct file *file, - unsigned int cmd, - unsigned long arg) -{ - return -EINVAL; -} -#endif - -static int msm_pcm_add_hwdep_dev(struct snd_soc_pcm_runtime *runtime) -{ - struct snd_hwdep *hwdep; - int rc; - char id[] = "NOIRQ_NN"; - - snprintf(id, sizeof(id), "NOIRQ_%d", runtime->pcm->device); - pr_debug("%s: pcm dev %d\n", __func__, runtime->pcm->device); - rc = snd_hwdep_new(runtime->card->snd_card, - &id[0], - HWDEP_FE_BASE + runtime->pcm->device, - &hwdep); - if (!hwdep || rc < 0) { - pr_err("%s: hwdep intf failed to create %s - hwdep\n", __func__, - id); - return rc; - } - - hwdep->iface = SNDRV_HWDEP_IFACE_AUDIO_BE; /* for lack of a FE iface */ - hwdep->private_data = runtime->pcm; /* of type struct snd_pcm */ - hwdep->ops.ioctl = msm_pcm_hwdep_ioctl; - hwdep->ops.ioctl_compat = msm_pcm_hwdep_compat_ioctl; - return 0; -} static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) { @@ -1170,9 +1027,7 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add app type controls failed %d\n", __func__, ret); } - ret = msm_pcm_add_hwdep_dev(rtd); - if (ret) - pr_err("%s: Could not add hw dep node\n", __func__); + pcm->nonatomic = true; exit: return ret; @@ -1185,9 +1040,6 @@ static struct snd_pcm_ops msm_pcm_ops = { .copy = msm_pcm_copy, .hw_params = msm_pcm_hw_params, .ioctl = msm_pcm_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = msm_pcm_compat_ioctl, -#endif .trigger = msm_pcm_trigger, .pointer = msm_pcm_pointer, .mmap = msm_pcm_mmap, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 0d01803e634d72f2256d2ac67813beef41c2359c..46a3324d2d6ba40d16299b4ad08adc36c97016e8 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -1448,13 +1448,12 @@ static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd) if (pdata) { if (!pdata->pcm) { pdata->pcm = rtd->pcm; - ret = snd_soc_add_platform_controls(rtd->platform, - pcm_compress_control, - ARRAY_SIZE - (pcm_compress_control)); - if (ret < 0) - pr_err("%s: failed add ctl %s. err = %d\n", - __func__, mixer_str, ret); + snd_soc_add_platform_controls(rtd->platform, + pcm_compress_control, + ARRAY_SIZE + (pcm_compress_control)); + pr_debug("%s: add control success plt = %pK\n", + __func__, rtd->platform); } } else { pr_err("%s: NULL pdata\n", __func__); @@ -1604,378 +1603,6 @@ done: return ret; } -static int msm_pcm_playback_pan_scale_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = sizeof(struct asm_stream_pan_ctrl_params); - return 0; -} - -static int msm_pcm_playback_pan_scale_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret = 0; - int len = 0; - int i = 0; - struct snd_soc_component *usr_info = snd_kcontrol_chip(kcontrol); - struct snd_soc_platform *platform; - struct msm_plat_data *pdata; - struct snd_pcm_substream *substream; - struct msm_audio *prtd; - struct asm_stream_pan_ctrl_params pan_param; - char *usr_value = NULL; - uint32_t *gain_ptr = NULL; - if (!usr_info) { - pr_err("%s: usr_info is null\n", __func__); - ret = -EINVAL; - goto done; - } - - platform = snd_soc_component_to_platform(usr_info); - if (!platform) { - pr_err("%s: platform is null\n", __func__); - ret = -EINVAL; - goto done; - } - pdata = dev_get_drvdata(platform->dev); - if (!pdata) { - pr_err("%s: pdata is null\n", __func__); - ret = -EINVAL; - goto done; - } - substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - if (!substream) { - pr_err("%s substream not found\n", __func__); - ret = -EINVAL; - goto done; - } - - if (!substream->runtime) { - pr_err("%s substream runtime not found\n", __func__); - ret = -EINVAL; - goto done; - } - prtd = substream->runtime->private_data; - if (!prtd) { - ret = -EINVAL; - goto done; - } - usr_value = (char *) ucontrol->value.bytes.data; - if (!usr_value) { - pr_err("%s ucontrol data is null\n", __func__); - ret = -EINVAL; - goto done; - } - memcpy(&pan_param.num_output_channels, &usr_value[len], - sizeof(pan_param.num_output_channels)); - len += sizeof(pan_param.num_output_channels); - if (pan_param.num_output_channels > - PCM_FORMAT_MAX_NUM_CHANNEL) { - ret = -EINVAL; - goto done; - } - memcpy(&pan_param.num_input_channels, &usr_value[len], - sizeof(pan_param.num_input_channels)); - len += sizeof(pan_param.num_input_channels); - if (pan_param.num_input_channels > - PCM_FORMAT_MAX_NUM_CHANNEL) { - ret = -EINVAL; - goto done; - } - - if (usr_value[len++]) { - memcpy(pan_param.output_channel_map, &usr_value[len], - (pan_param.num_output_channels * - sizeof(pan_param.output_channel_map[0]))); - len += (pan_param.num_output_channels * - sizeof(pan_param.output_channel_map[0])); - } - if (usr_value[len++]) { - memcpy(pan_param.input_channel_map, &usr_value[len], - (pan_param.num_input_channels * - sizeof(pan_param.input_channel_map[0]))); - len += (pan_param.num_input_channels * - sizeof(pan_param.input_channel_map[0])); - } - if (usr_value[len++]) { - gain_ptr = (uint32_t *) &usr_value[len]; - for (i = 0; i < pan_param.num_output_channels * - pan_param.num_input_channels; i++) { - pan_param.gain[i] = - !(gain_ptr[i] > 0) ? - 0 : 2 << 13; - len += sizeof(pan_param.gain[i]); - } - len += (pan_param.num_input_channels * - pan_param.num_output_channels * sizeof(pan_param.gain[0])); - } - - ret = q6asm_set_mfc_panning_params(prtd->audio_client, - &pan_param); - len -= pan_param.num_output_channels * - pan_param.num_input_channels * sizeof(pan_param.gain[0]); - if (gain_ptr) { - for (i = 0; i < pan_param.num_output_channels * - pan_param.num_input_channels; i++) { - /* - * The data userspace passes is already in Q14 format. - * For volume gain is in Q28. - */ - pan_param.gain[i] = - (gain_ptr[i]) << 14; - len += sizeof(pan_param.gain[i]); - } - } - ret = q6asm_set_vol_ctrl_gain_pair(prtd->audio_client, - &pan_param); - -done: - return ret; -} - -static int msm_pcm_playback_pan_scale_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return 0; -} - -static int msm_add_stream_pan_scale_controls(struct snd_soc_pcm_runtime *rtd) -{ - const char *playback_mixer_ctl_name = "Audio Stream"; - const char *deviceNo = "NN"; - const char *suffix = "Pan Scale Control"; - char *mixer_str = NULL; - int ctl_len; - int ret = 0; - struct msm_plat_data *pdata; - struct snd_kcontrol_new pan_scale_control[1] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "?", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = msm_pcm_playback_pan_scale_ctl_info, - .get = msm_pcm_playback_pan_scale_ctl_get, - .put = msm_pcm_playback_pan_scale_ctl_put, - .private_value = 0, - } - }; - - if (!rtd) { - pr_err("%s: NULL rtd\n", __func__); - return -EINVAL; - } - - ctl_len = strlen(playback_mixer_ctl_name) + 1 + - strlen(deviceNo) + 1 + strlen(suffix) + 1; - mixer_str = kzalloc(ctl_len, GFP_KERNEL); - if (!mixer_str) { - ret = -ENOMEM; - goto done; - } - - snprintf(mixer_str, ctl_len, "%s %d %s", - playback_mixer_ctl_name, rtd->pcm->device, suffix); - pan_scale_control[0].name = mixer_str; - pan_scale_control[0].private_value = rtd->dai_link->be_id; - pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); - pdata = dev_get_drvdata(rtd->platform->dev); - if (pdata) { - if (!pdata->pcm) - pdata->pcm = rtd->pcm; - ret = snd_soc_add_platform_controls(rtd->platform, - pan_scale_control, - ARRAY_SIZE - (pan_scale_control)); - if (ret < 0) - pr_err("%s: failed add ctl %s. err = %d\n", - __func__, mixer_str, ret); - } else { - pr_err("%s: NULL pdata\n", __func__); - ret = -EINVAL; - } - - kfree(mixer_str); -done: - return ret; - -} - -static int msm_pcm_playback_dnmix_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return 0; -} - -static int msm_pcm_playback_dnmix_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = sizeof(struct asm_stream_pan_ctrl_params); - return 0; -} - -static int msm_pcm_playback_dnmix_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int ret = 0; - int len = 0; - - struct snd_soc_component *usr_info = snd_kcontrol_chip(kcontrol); - struct snd_soc_platform *platform; - struct msm_plat_data *pdata; - struct snd_pcm_substream *substream; - struct msm_audio *prtd; - struct asm_stream_pan_ctrl_params dnmix_param; - char *usr_value; - int be_id = 0; - int stream_id = 0; - - if (!usr_info) { - pr_err("%s usr_info is null\n", __func__); - ret = -EINVAL; - goto done; - } - platform = snd_soc_component_to_platform(usr_info); - if (!platform) { - pr_err("%s platform is null\n", __func__); - ret = -EINVAL; - goto done; - } - pdata = dev_get_drvdata(platform->dev); - if (!pdata) { - pr_err("%s pdata is null\n", __func__); - ret = -EINVAL; - goto done; - } - substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - if (!substream) { - pr_err("%s substream not found\n", __func__); - ret = -EINVAL; - goto done; - } - if (!substream->runtime) { - pr_err("%s substream runtime not found\n", __func__); - ret = -EINVAL; - goto done; - } - prtd = substream->runtime->private_data; - if (!prtd) { - ret = -EINVAL; - goto done; - } - usr_value = (char *) ucontrol->value.bytes.data; - if (!usr_value) { - pr_err("%s usrvalue is null\n", __func__); - goto done; - } - memcpy(&be_id, usr_value, sizeof(be_id)); - len += sizeof(be_id); - stream_id = prtd->audio_client->session; - memcpy(&dnmix_param.num_output_channels, &usr_value[len], - sizeof(dnmix_param.num_output_channels)); - len += sizeof(dnmix_param.num_output_channels); - if (dnmix_param.num_output_channels > - PCM_FORMAT_MAX_NUM_CHANNEL) { - ret = -EINVAL; - goto done; - } - memcpy(&dnmix_param.num_input_channels, &usr_value[len], - sizeof(dnmix_param.num_input_channels)); - len += sizeof(dnmix_param.num_input_channels); - if (dnmix_param.num_input_channels > - PCM_FORMAT_MAX_NUM_CHANNEL) { - ret = -EINVAL; - goto done; - } - if (usr_value[len++]) { - memcpy(dnmix_param.output_channel_map, &usr_value[len], - (dnmix_param.num_output_channels * - sizeof(dnmix_param.output_channel_map[0]))); - len += (dnmix_param.num_output_channels * - sizeof(dnmix_param.output_channel_map[0])); - } - if (usr_value[len++]) { - memcpy(dnmix_param.input_channel_map, &usr_value[len], - (dnmix_param.num_input_channels * - sizeof(dnmix_param.input_channel_map[0]))); - len += (dnmix_param.num_input_channels * - sizeof(dnmix_param.input_channel_map[0])); - } - if (usr_value[len++]) { - memcpy(dnmix_param.gain, (uint32_t *) &usr_value[len], - (dnmix_param.num_input_channels * - dnmix_param.num_output_channels * - sizeof(dnmix_param.gain[0]))); - len += (dnmix_param.num_input_channels * - dnmix_param.num_output_channels * sizeof(dnmix_param.gain[0])); - } - msm_routing_set_downmix_control_data(be_id, - stream_id, - &dnmix_param); - -done: - return ret; -} - -static int msm_add_device_down_mix_controls(struct snd_soc_pcm_runtime *rtd) -{ - const char *playback_mixer_ctl_name = "Audio Device"; - const char *deviceNo = "NN"; - const char *suffix = "Downmix Control"; - char *mixer_str = NULL; - int ctl_len = 0, ret = 0; - struct msm_plat_data *pdata; - struct snd_kcontrol_new device_downmix_control[1] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "?", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = msm_pcm_playback_dnmix_ctl_info, - .get = msm_pcm_playback_dnmix_ctl_get, - .put = msm_pcm_playback_dnmix_ctl_put, - .private_value = 0, - } - }; - - if (!rtd) { - pr_err("%s NULL rtd\n", __func__); - ret = -EINVAL; - goto done; - } - ctl_len = strlen(playback_mixer_ctl_name) + 1 + - strlen(deviceNo) + 1 + strlen(suffix) + 1; - mixer_str = kzalloc(ctl_len, GFP_KERNEL); - if (!mixer_str) { - ret = -ENOMEM; - goto done; - } - - snprintf(mixer_str, ctl_len, "%s %d %s", - playback_mixer_ctl_name, rtd->pcm->device, suffix); - device_downmix_control[0].name = mixer_str; - device_downmix_control[0].private_value = rtd->dai_link->be_id; - pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); - pdata = dev_get_drvdata(rtd->platform->dev); - if (pdata) { - if (!pdata->pcm) - pdata->pcm = rtd->pcm; - ret = snd_soc_add_platform_controls(rtd->platform, - device_downmix_control, - ARRAY_SIZE - (device_downmix_control)); - if (ret < 0) - pr_err("%s: failed add ctl %s. err = %d\n", - __func__, mixer_str, ret); - } else { - pr_err("%s: NULL pdata\n", __func__); - ret = -EINVAL; - } - kfree(mixer_str); -done: - return ret; -} - static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2092,14 +1719,6 @@ static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd) if (ret) pr_err("%s: pcm add app type controls failed:%d\n", __func__, ret); - ret = msm_add_stream_pan_scale_controls(rtd); - if (ret) - pr_err("%s: pcm add pan scale controls failed:%d\n", - __func__, ret); - ret = msm_add_device_down_mix_controls(rtd); - if (ret) - pr_err("%s: pcm add dnmix controls failed:%d\n", - __func__, ret); return ret; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 6f635493031f71b8c9d8840a4fd082745c6b05bf..e8873f942c0d348423607151d5b550dfe1d76625 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include @@ -35,9 +40,8 @@ #include #include #include -#include -#include +#include "msm-ahc-config.h" #include "msm-pcm-routing-v2.h" #include "msm-pcm-routing-devdep.h" #include "msm-qti-pp-config.h" @@ -82,6 +86,13 @@ static int msm_route_ext_ec_ref; static bool is_custom_stereo_on; static bool is_ds2_on; static bool swap_ch; +static int sony_custom_stereo_mode; + +static struct mute_params { + uint32_t duration; + uint32_t flag_ch1; + uint32_t flag_ch2; +} mute = {0, 0, 0}; #define WEIGHT_0_DB 0x4000 /* all the FEs which can support channel mixer */ @@ -120,13 +131,17 @@ static const char * const lsm_port_text[] = { }; struct msm_pcm_route_bdai_pp_params { + u16 port_id; /* AFE port ID */ unsigned long pp_params_config; bool mute_on; int latency; }; static struct msm_pcm_route_bdai_pp_params - msm_bedais_pp_params[MSM_BACKEND_DAI_MAX]; + msm_bedais_pp_params[MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX] = { + {HDMI_RX, 0, 0, 0}, + {DISPLAY_PORT_RX, 0, 0, 0}, +}; /* * The be_dai_name_table is passed to HAL so that it can specify the @@ -140,7 +155,6 @@ struct msm_pcm_route_bdai_name { }; static struct msm_pcm_route_bdai_name be_dai_name_table[MSM_BACKEND_DAI_MAX]; -static bool msm_pcm_routing_test_pp_param(int be_idx, long param_bit); static int msm_routing_send_device_pp_params(int port_id, int copp_idx, int fe_id); @@ -220,6 +234,13 @@ static void msm_pcm_routing_cfg_pp(int port_id, int copp_idx, int topology, pr_err("%s: topo_id 0x%x, port %d, copp %d, rc %d\n", __func__, topology, port_id, copp_idx, rc); break; + case ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP_SOMC_HP: + if (port_id == AHC_PORT_ID) { + pr_debug("%s: AHC supporting topology 0x%X\n", + __func__, topology); + msm_routing_ahc_set_copp_idx(copp_idx); + } + break; default: /* custom topology specific feature param handlers */ break; @@ -251,6 +272,13 @@ static void msm_pcm_routing_deinit_pp(int port_id, int topology) pr_debug("%s: TOPOLOGY_ID_AUDIOSPHERE\n", __func__); msm_qti_pp_asphere_deinit(port_id); break; + case ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP_SOMC_HP: + if (port_id == AHC_PORT_ID) { + pr_debug("%s: AHC supporting topology 0x%X\n", + __func__, topology); + msm_routing_ahc_set_copp_idx(-1); + } + break; default: /* custom topology specific feature deinit handlers */ break; @@ -261,28 +289,39 @@ static void msm_pcm_routng_cfg_matrix_map_pp(struct route_payload payload, int path_type, int perf_mode) { int itr = 0, rc = 0; - if ((path_type == ADM_PATH_PLAYBACK) && - (perf_mode == LEGACY_PCM_MODE) && - is_custom_stereo_on) { + if ((path_type != ADM_PATH_PLAYBACK) || + (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) || + !is_custom_stereo_on) + return; + for (itr = 0; itr < payload.num_copps; itr++) { if ((payload.port_id[itr] != SLIMBUS_0_RX) && (payload.port_id[itr] != RT_PROXY_PORT_001_RX)) { continue; } - rc = msm_qti_pp_send_stereo_to_custom_stereo_cmd( - payload.port_id[itr], - payload.copp_idx[itr], - payload.session_id, - Q14_GAIN_ZERO_POINT_FIVE, - Q14_GAIN_ZERO_POINT_FIVE, - Q14_GAIN_ZERO_POINT_FIVE, - Q14_GAIN_ZERO_POINT_FIVE); + if (sony_custom_stereo_mode == SONY_CUSTOM_STEREO_MIX) + rc = msm_qti_pp_send_stereo_to_custom_stereo_cmd( + payload.port_id[itr], + payload.copp_idx[itr], + payload.session_id, + Q14_GAIN_ZERO_POINT_FIVE, + Q14_GAIN_ZERO_POINT_FIVE, + Q14_GAIN_ZERO_POINT_FIVE, + Q14_GAIN_ZERO_POINT_FIVE); + else + rc = msm_qti_pp_send_stereo_to_custom_stereo_cmd( + payload.port_id[itr], + payload.copp_idx[itr], + payload.session_id, + 0, + Q14_GAIN_UNITY, + Q14_GAIN_UNITY, + 0); if (rc < 0) pr_err("%s: err setting custom stereo\n", __func__); } - } } #define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID @@ -603,27 +642,6 @@ static struct msm_pcm_routing_fdai_data {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, /* MULTIMEDIA20 */ - {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, - {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, - /* MULTIMEDIA21 */ - {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, - {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, - /* MULTIMEDIA22 */ - {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, - {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, - /* MULTIMEDIA23 */ - {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, - {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, - /* MULTIMEDIA24 */ - {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, - {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, - /* MULTIMEDIA25 */ - {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, - {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, - /* MULTIMEDIA26 */ - {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, - {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, - /* MULTIMEDIA27 */ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} }, {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } }, /* CS_VOICE */ @@ -973,7 +991,7 @@ static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type, uint32_t passthr_mode) { int i, port_type, j, num_copps = 0; - struct route_payload payload = { {0} }; + struct route_payload payload; port_type = ((path_type == ADM_PATH_PLAYBACK || path_type == ADM_PATH_COMPRESSED_RX) ? @@ -1003,11 +1021,6 @@ static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type, fe_dai_app_type_cfg [fedai_id][sess_type][i] .sample_rate; - if (msm_pcm_routing_test_pp_param(i, - ADM_PP_PARAM_LIMITER_BIT)) - set_bit(ADM_STATUS_LIMITER, - &payload.route_status - [num_copps]); num_copps++; } } @@ -1229,11 +1242,6 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode, fe_dai_app_type_cfg [fe_id][session_type][i] .sample_rate; - if (msm_pcm_routing_test_pp_param(i, - ADM_PP_PARAM_LIMITER_BIT)) - set_bit(ADM_STATUS_LIMITER, - &payload.route_status - [num_copps]); num_copps++; } } @@ -1358,6 +1366,7 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, uint16_t bits_per_sample = 16; uint32_t passthr_mode = LEGACY_PCM; int ret = 0; + bool is_copp_24bit = false; if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) { /* bad ID assigned in machine driver */ @@ -1402,6 +1411,8 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, bits_per_sample = msm_routing_get_bit_width( msm_bedais[i].format); + if (bits_per_sample == 24) + is_copp_24bit = true; app_type = fe_dai_app_type_cfg[fedai_id][session_type][i].app_type; @@ -1416,6 +1427,11 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, } else sample_rate = msm_bedais[i].sample_rate; + if (path_type == 2) { + if (is_copp_24bit == true) + bits_per_sample = 24; + } + acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type][i] .acdb_dev_id; @@ -1464,11 +1480,6 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, fe_dai_app_type_cfg [fedai_id][session_type] [i].sample_rate; - if (msm_pcm_routing_test_pp_param(i, - ADM_PP_PARAM_LIMITER_BIT)) - set_bit(ADM_STATUS_LIMITER, - &payload.route_status - [num_copps]); num_copps++; } } @@ -1559,7 +1570,9 @@ void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type) clear_bit(idx, &session_copp_map[fedai_id][session_type][i]); if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology || - DS2_ADM_COPP_TOPOLOGY_ID == topology) && + DS2_ADM_COPP_TOPOLOGY_ID == topology || + ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP_SOMC_HP + == topology) && (fdai->perf_mode == LEGACY_PCM_MODE) && (msm_bedais[i].passthr_mode[fedai_id] == LEGACY_PCM)) @@ -1598,6 +1611,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set) struct msm_pcm_routing_fdai_data *fdai; uint32_t passthr_mode; bool is_lsm; + bool is_copp_24bit = false; pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set); @@ -1666,6 +1680,8 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set) bits_per_sample = msm_routing_get_bit_width( msm_bedais[reg].format); + if (bits_per_sample == 24) + is_copp_24bit = true; app_type = fe_dai_app_type_cfg[val][session_type][reg].app_type; @@ -1687,6 +1703,10 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set) app_type_cfg[app_type_idx].bit_width; } else sample_rate = msm_bedais[reg].sample_rate; + if (path_type == 2) { + if (is_copp_24bit == true) + bits_per_sample = 24; + } topology = msm_routing_get_adm_topology(val, session_type, @@ -3675,11 +3695,6 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 = msm_route_ec_ref_rx_enum[0], msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); -static const struct snd_kcontrol_new ext_ec_ref_mux_ul16 = - SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL16 MUX Mux", - msm_route_ec_ref_rx_enum[0], - msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); - static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 = SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux", msm_route_ec_ref_rx_enum[0], @@ -3838,9 +3853,6 @@ static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_I2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { @@ -3901,9 +3913,6 @@ static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_I2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { @@ -3964,9 +3973,7 @@ static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SPDIF_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), + }; static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = { @@ -4018,9 +4025,6 @@ static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_2_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = { @@ -4081,9 +4085,6 @@ static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_5_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { @@ -4144,24 +4145,6 @@ static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SLIMBUS_0_RX, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SLIMBUS_0_RX, - MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia23", MSM_BACKEND_DAI_SLIMBUS_0_RX, - MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia24", MSM_BACKEND_DAI_SLIMBUS_0_RX, - MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_SLIMBUS_0_RX, - MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_0_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = { @@ -4222,9 +4205,6 @@ static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_MI2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { @@ -4285,9 +4265,6 @@ static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { @@ -4348,9 +4325,6 @@ static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUINARY_MI2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { @@ -4405,9 +4379,6 @@ static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx2_mixer_controls[] = { @@ -4474,9 +4445,6 @@ static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { @@ -4537,9 +4505,6 @@ static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_MI2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = { @@ -4591,9 +4556,6 @@ static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT0_MI2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int4_mi2s_rx_mixer_controls[] = { @@ -4645,9 +4607,6 @@ static const struct snd_kcontrol_new int4_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT4_MI2S_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new hdmi_mixer_controls[] = { @@ -4708,24 +4667,6 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_HDMI_RX, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_HDMI_RX, - MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia23", MSM_BACKEND_DAI_HDMI_RX, - MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia24", MSM_BACKEND_DAI_HDMI_RX, - MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_HDMI_RX, - MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_HDMI_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new display_port_mixer_controls[] = { @@ -4777,9 +4718,6 @@ static const struct snd_kcontrol_new display_port_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_DISPLAY_PORT_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; /* incall music delivery mixer */ @@ -4877,24 +4815,6 @@ static const struct snd_kcontrol_new slimbus_6_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SLIMBUS_6_RX, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SLIMBUS_6_RX, - MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia23", MSM_BACKEND_DAI_SLIMBUS_6_RX, - MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia24", MSM_BACKEND_DAI_SLIMBUS_6_RX, - MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_SLIMBUS_6_RX, - MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_6_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_7_rx_mixer_controls[] = { @@ -4946,24 +4866,6 @@ static const struct snd_kcontrol_new slimbus_7_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SLIMBUS_7_RX, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SLIMBUS_7_RX, - MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia23", MSM_BACKEND_DAI_SLIMBUS_7_RX, - MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia24", MSM_BACKEND_DAI_SLIMBUS_7_RX, - MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_SLIMBUS_7_RX, - MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_7_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new usb_audio_rx_mixer_controls[] = { @@ -5015,9 +4917,6 @@ static const struct snd_kcontrol_new usb_audio_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_USB_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = { @@ -5078,9 +4977,6 @@ static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT_BT_SCO_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = { @@ -5132,9 +5028,6 @@ static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT_BT_A2DP_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = { @@ -5195,9 +5088,6 @@ static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT_FM_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = { @@ -5258,9 +5148,6 @@ static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_AFE_PCM_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = { @@ -5321,12 +5208,6 @@ static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_AUXPCM_RX, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_AUXPCM_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = { @@ -5387,12 +5268,6 @@ static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_AUXPCM_RX, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_AUXPCM_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = { @@ -5444,9 +5319,6 @@ static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_AUXPCM_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_auxpcm_rx_mixer_controls[] = { @@ -5498,9 +5370,6 @@ static const struct snd_kcontrol_new quat_auxpcm_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = { @@ -5552,12 +5421,6 @@ static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_0, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_0, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = { @@ -5609,12 +5472,6 @@ static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_1, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_1, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = { @@ -5666,12 +5523,6 @@ static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_2, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_2, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = { @@ -5723,12 +5574,6 @@ static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_3, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_3, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = { @@ -5831,12 +5676,6 @@ static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_0, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_0, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = { @@ -5888,12 +5727,6 @@ static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_1, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_1, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = { @@ -5945,12 +5778,6 @@ static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_2, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_2, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = { @@ -6002,12 +5829,6 @@ static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_3, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_3, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = { @@ -6110,12 +5931,6 @@ static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_0, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_0, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_tx_0_mixer_controls[] = { @@ -6218,12 +6033,6 @@ static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_1, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_1, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = { @@ -6275,12 +6084,6 @@ static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_2, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_2, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = { @@ -6332,12 +6135,6 @@ static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_3, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_3, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = { @@ -6389,12 +6186,6 @@ static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_4, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_4, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = { @@ -6449,12 +6240,6 @@ static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_0, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_0, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = { @@ -6560,12 +6345,6 @@ static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_1, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_1, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = { @@ -6620,12 +6399,6 @@ static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_2, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_2, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = { @@ -6680,12 +6453,6 @@ static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_3, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_3, - MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul1_mixer_controls[] = { @@ -7375,114 +7142,6 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = { msm_routing_put_audio_mixer), }; -static const struct snd_kcontrol_new mmul16_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX", MSM_BACKEND_DAI_AUXPCM_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, - MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), -}; - static const struct snd_kcontrol_new mmul9_mixer_controls[] = { SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, @@ -7672,75 +7331,6 @@ static const struct snd_kcontrol_new mmul20_mixer_controls[] = { msm_routing_put_audio_mixer), }; -static const struct snd_kcontrol_new mmul21_mixer_controls[] = { - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, - MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), -}; - -static const struct snd_kcontrol_new mmul27_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, - MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, - MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, - MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer, - msm_routing_put_audio_mixer), -}; - static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = { SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, @@ -10262,22 +9852,6 @@ static const struct snd_kcontrol_new quat_tdm_rx_0_port_mixer_controls[] = { MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_0, - MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_0, - MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_0, - MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_0, - MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, @@ -10345,22 +9919,6 @@ static const struct snd_kcontrol_new quat_tdm_rx_1_port_mixer_controls[] = { MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_1, - MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_1, - MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_1, - MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_1, - MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, @@ -10428,22 +9986,6 @@ static const struct snd_kcontrol_new quat_tdm_rx_2_port_mixer_controls[] = { MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_2, - MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_2, - MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_2, - MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_2, - MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, @@ -10511,22 +10053,6 @@ static const struct snd_kcontrol_new quat_tdm_rx_3_port_mixer_controls[] = { MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_3, - MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_3, - MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_3, - MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_3, - MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, - msm_routing_get_port_mixer, - msm_routing_put_port_mixer), SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, @@ -11025,14 +10551,10 @@ static int msm_routing_put_stereo_to_custom_stereo_control( session_id = fe_dai_map[i][SESSION_TYPE_RX].strm_id; if (is_custom_stereo_on) { - op_FL_ip_FL_weight = - Q14_GAIN_ZERO_POINT_FIVE; - op_FL_ip_FR_weight = - Q14_GAIN_ZERO_POINT_FIVE; - op_FR_ip_FL_weight = - Q14_GAIN_ZERO_POINT_FIVE; - op_FR_ip_FR_weight = - Q14_GAIN_ZERO_POINT_FIVE; + op_FL_ip_FL_weight = 0; + op_FL_ip_FR_weight = Q14_GAIN_UNITY; + op_FR_ip_FL_weight = Q14_GAIN_UNITY; + op_FR_ip_FR_weight = 0; } else { op_FL_ip_FL_weight = Q14_GAIN_UNITY; op_FL_ip_FR_weight = 0; @@ -11084,6 +10606,117 @@ static const struct snd_kcontrol_new stereo_to_custom_stereo_controls[] = { msm_routing_put_stereo_to_custom_stereo_control), }; +static int msm_routing_get_sony_stereo_to_custom_stereo_control( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = sony_custom_stereo_mode; + return 0; +} + +static int msm_routing_put_sony_stereo_to_custom_stereo_control( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int mode = 0, i = 0, rc = 0, idx = 0; + int be_index = 0, port_id, topo_id; + unsigned int session_id = 0; + uint16_t op_FL_ip_FL_weight; + uint16_t op_FL_ip_FR_weight; + uint16_t op_FR_ip_FL_weight; + uint16_t op_FR_ip_FR_weight; + mode = ucontrol->value.integer.value[0]; + pr_debug("%s E mode %d\n", __func__, mode); + + if (sony_custom_stereo_mode == mode) { + pr_err("%s: sony_custom_stereo_mode %d, mode %d\n", + __func__, sony_custom_stereo_mode, mode); + return 0; + } + sony_custom_stereo_mode = mode; + is_custom_stereo_on = (mode == SONY_CUSTOM_STEREO_NORMAL) ? false : true; + pr_debug("%s:sony_custom_stereo_mode %d\n", __func__, sony_custom_stereo_mode); + if (sony_custom_stereo_mode == SONY_CUSTOM_STEREO_MIX) { + op_FL_ip_FL_weight = Q14_GAIN_ZERO_POINT_FIVE; + op_FL_ip_FR_weight = Q14_GAIN_ZERO_POINT_FIVE; + op_FR_ip_FL_weight = Q14_GAIN_ZERO_POINT_FIVE; + op_FR_ip_FR_weight = Q14_GAIN_ZERO_POINT_FIVE; + } else if (sony_custom_stereo_mode == SONY_CUSTOM_STEREO_SWAP) { + op_FL_ip_FL_weight = 0; + op_FL_ip_FR_weight = Q14_GAIN_UNITY; + op_FR_ip_FL_weight = Q14_GAIN_UNITY; + op_FR_ip_FR_weight = 0; + } else { + op_FL_ip_FL_weight = Q14_GAIN_UNITY; + op_FL_ip_FR_weight = 0; + op_FR_ip_FL_weight = 0; + op_FR_ip_FR_weight = Q14_GAIN_UNITY; + } + for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) { + port_id = msm_bedais[be_index].port_id; + if (!msm_bedais[be_index].active) + continue; + if ((port_id != SLIMBUS_0_RX) && + (port_id != RT_PROXY_PORT_001_RX)) + continue; + + for_each_set_bit(i, &msm_bedais[be_index].fe_sessions[0], + MSM_FRONTEND_DAI_MM_SIZE) { + if (fe_dai_map[i][SESSION_TYPE_RX].perf_mode == + ULTRA_LOW_LATENCY_PCM_MODE) { + pr_err("%s: pcm mode error:%d\n", __func__, + fe_dai_map[i][SESSION_TYPE_RX].perf_mode); + continue; + } + session_id = + fe_dai_map[i][SESSION_TYPE_RX].strm_id; + for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) { + unsigned long copp = + session_copp_map[i] + [SESSION_TYPE_RX][be_index]; + if (!test_bit(idx, &copp)) + continue; + topo_id = adm_get_topology_for_port_copp_idx( + msm_bedais[be_index].port_id, idx); + if (topo_id < 0) + pr_debug("%s:Err:custom stereo topo %d", + __func__, topo_id); + pr_debug("idx %d\n", idx); + if (topo_id == DS2_ADM_COPP_TOPOLOGY_ID) + rc = msm_ds2_dap_set_custom_stereo_onoff + (msm_bedais[be_index].port_id, + idx, is_custom_stereo_on); + else if (topo_id == DOLBY_ADM_COPP_TOPOLOGY_ID) + rc = dolby_dap_set_custom_stereo_onoff( + msm_bedais[be_index].port_id, + idx, is_custom_stereo_on); + else + rc = msm_qti_pp_send_stereo_to_custom_stereo_cmd + (msm_bedais[be_index].port_id, + idx, session_id, + op_FL_ip_FL_weight, + op_FL_ip_FR_weight, + op_FR_ip_FL_weight, + op_FR_ip_FR_weight); + if (rc < 0) + pr_err("%s: err setting custom stereo\n", + __func__); + } + + } + } + return 0; +} +static const char *const sony_custom_stereo_text[] = {"Off", "Mix", "Swap"}; +static const struct soc_enum sony_custom_stereo_channel_enum = + SOC_ENUM_SINGLE_EXT(3, sony_custom_stereo_text); +static const struct snd_kcontrol_new sony_stereo_to_custom_stereo_controls[] = { + SOC_ENUM_EXT("Set Custom Stereo", + sony_custom_stereo_channel_enum, + msm_routing_get_sony_stereo_to_custom_stereo_control, + msm_routing_put_sony_stereo_to_custom_stereo_control), +}; + static int msm_routing_get_app_type_cfg_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -11119,7 +10752,7 @@ static int msm_routing_put_app_type_cfg_control(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new app_type_cfg_controls[] = { SOC_SINGLE_MULTI_EXT("App Type Config", SND_SOC_NOPM, 0, - 0x7FFFFFFF, 0, 128, msm_routing_get_app_type_cfg_control, + 0xFFFFFFFF, 0, 128, msm_routing_get_app_type_cfg_control, msm_routing_put_app_type_cfg_control), }; @@ -11245,6 +10878,79 @@ static struct snd_kcontrol_new msm_voc_session_controls[] = { msm_voc_session_id_put), }; +static int msm_adm_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = mute.duration; + ucontrol->value.integer.value[1] = mute.flag_ch1; + ucontrol->value.integer.value[2] = mute.flag_ch2; + + pr_debug("%s: mute = {%d, %d, %d}\n", __func__, + mute.duration, mute.flag_ch1, mute.flag_ch2); + + return 0; +} + +static int msm_adm_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = 0; + int be_index = 0; + int fedai_id = 0; + int port_id = 0; + int session_id = 0; + struct msm_pcm_routing_bdai_data *bedai; + + mute.duration = (uint32_t)ucontrol->value.integer.value[0]; + mute.flag_ch1 = (uint32_t)ucontrol->value.integer.value[1]; + mute.flag_ch2 = (uint32_t)ucontrol->value.integer.value[2]; + + if ((mute.duration > 0xffff) || + (mute.flag_ch1 > 1) || (mute.flag_ch2 > 1)) { + pr_err("%s Invalid arguments. mute={%x, %x, %x}", + __func__, mute.duration, mute.flag_ch1, mute.flag_ch2); + ret = -EINVAL; + goto done; + } + + for (fedai_id = 0; fedai_id < MSM_FRONTEND_DAI_MM_SIZE; fedai_id++) { + if (fe_dai_map[fedai_id][SESSION_TYPE_RX].strm_id != + INVALID_SESSION) { + session_id = fe_dai_map[fedai_id][SESSION_TYPE_RX].strm_id; + + for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) { + if (!msm_bedais[be_index].active) + continue; + + bedai = &msm_bedais[be_index]; + pr_debug("%s: be_index=%d, bedai->fe_sessions=%#x\n", __func__, + be_index, (int)bedai->fe_sessions[0]); + + port_id = msm_bedais[be_index].port_id; + + pr_debug("%s: fedai_id=%d, strm_id=%d, port_id=%d, session_id=%d, mute={%d, %d, %d}\n", + __func__, fedai_id, + fe_dai_map[fedai_id][SESSION_TYPE_RX].strm_id, + port_id, session_id, mute.duration, + mute.flag_ch1, mute.flag_ch2); + adm_matrix_mute(port_id, session_id, mute.duration, + mute.flag_ch1, mute.flag_ch2); + } + } else { + ; /* do nothing */ + } + } + +done: + return ret; +} + +static struct snd_kcontrol_new msm_adm_mute_controls[] = { + SOC_SINGLE_MULTI_EXT("Matrix Mute", SND_SOC_NOPM, 0, + 0xFFFFFFFF, 0, 3, msm_adm_mute_get, + msm_adm_mute_put), +}; + static int msm_sound_focus_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -11843,12 +11549,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_IN("MM_DL15", "MultiMedia15 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("MM_DL16", "MultiMedia16 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("MM_DL20", "MultiMedia20 Playback", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_IN("MM_DL21", "MultiMedia21 Playback", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_IN("MM_DL22", "MultiMedia22 Playback", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_IN("MM_DL23", "MultiMedia23 Playback", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_IN("MM_DL24", "MultiMedia24 Playback", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_IN("MM_DL25", "MultiMedia25 Playback", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_IN("MM_DL26", "MultiMedia26 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0), @@ -11858,13 +11558,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_OUT("MM_UL16", "MultiMedia16 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("MM_UL20", "MultiMedia20 Capture", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_OUT("MM_UL21", "MultiMedia21 Capture", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_OUT("MM_UL27", "MultiMedia27 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0), @@ -12597,8 +12294,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia9 Mixer", SND_SOC_NOPM, 0, 0, mmul9_mixer_controls, ARRAY_SIZE(mmul9_mixer_controls)), - SND_SOC_DAPM_MIXER("MultiMedia16 Mixer", SND_SOC_NOPM, 0, 0, - mmul16_mixer_controls, ARRAY_SIZE(mmul16_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0, mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0, @@ -12607,10 +12302,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { mmul19_mixer_controls, ARRAY_SIZE(mmul19_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia20 Mixer", SND_SOC_NOPM, 0, 0, mmul20_mixer_controls, ARRAY_SIZE(mmul20_mixer_controls)), - SND_SOC_DAPM_MIXER("MultiMedia21 Mixer", SND_SOC_NOPM, 0, 0, - mmul21_mixer_controls, ARRAY_SIZE(mmul21_mixer_controls)), - SND_SOC_DAPM_MIXER("MultiMedia27 Mixer", SND_SOC_NOPM, 0, 0, - mmul27_mixer_controls, ARRAY_SIZE(mmul27_mixer_controls)), SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0, auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)), SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0, @@ -12933,8 +12624,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { &ext_ec_ref_mux_ul8), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul9), - SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL16 MUX", SND_SOC_NOPM, 0, 0, - &ext_ec_ref_mux_ul16), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul17), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL18 MUX", SND_SOC_NOPM, 0, 0, @@ -12960,7 +12649,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"PRI_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"}, {"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12979,7 +12667,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SEC_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"}, {"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -12998,12 +12685,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_0_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SLIMBUS_0_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SLIMBUS_0_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SLIMBUS_0_RX Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"SLIMBUS_0_RX Audio Mixer", "MultiMedia22", "MM_DL22"}, - {"SLIMBUS_0_RX Audio Mixer", "MultiMedia23", "MM_DL23"}, - {"SLIMBUS_0_RX Audio Mixer", "MultiMedia24", "MM_DL24"}, - {"SLIMBUS_0_RX Audio Mixer", "MultiMedia25", "MM_DL25"}, - {"SLIMBUS_0_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"}, {"SLIMBUS_2_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13022,7 +12703,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_2_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SLIMBUS_2_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SLIMBUS_2_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SLIMBUS_2_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_2_RX", NULL, "SLIMBUS_2_RX Audio Mixer"}, {"SLIMBUS_5_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13041,7 +12721,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_5_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SLIMBUS_5_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SLIMBUS_5_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SLIMBUS_5_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_5_RX", NULL, "SLIMBUS_5_RX Audio Mixer"}, {"HDMI Mixer", "MultiMedia1", "MM_DL1"}, @@ -13060,12 +12739,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"HDMI Mixer", "MultiMedia14", "MM_DL14"}, {"HDMI Mixer", "MultiMedia15", "MM_DL15"}, {"HDMI Mixer", "MultiMedia16", "MM_DL16"}, - {"HDMI Mixer", "MultiMedia21", "MM_DL21"}, - {"HDMI Mixer", "MultiMedia22", "MM_DL22"}, - {"HDMI Mixer", "MultiMedia23", "MM_DL23"}, - {"HDMI Mixer", "MultiMedia24", "MM_DL24"}, - {"HDMI Mixer", "MultiMedia25", "MM_DL25"}, - {"HDMI Mixer", "MultiMedia26", "MM_DL26"}, {"HDMI", NULL, "HDMI Mixer"}, {"DISPLAY_PORT Mixer", "MultiMedia1", "MM_DL1"}, @@ -13084,7 +12757,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"DISPLAY_PORT Mixer", "MultiMedia14", "MM_DL14"}, {"DISPLAY_PORT Mixer", "MultiMedia15", "MM_DL15"}, {"DISPLAY_PORT Mixer", "MultiMedia16", "MM_DL16"}, - {"DISPLAY_PORT Mixer", "MultiMedia26", "MM_DL26"}, {"DISPLAY_PORT", NULL, "DISPLAY_PORT Mixer"}, {"SPDIF_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13103,7 +12775,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SPDIF_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SPDIF_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SPDIF_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SPDIF_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SPDIF_RX", NULL, "SPDIF_RX Audio Mixer"}, /* incall */ @@ -13139,12 +12810,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_6_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SLIMBUS_6_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SLIMBUS_6_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SLIMBUS_6_RX Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"SLIMBUS_6_RX Audio Mixer", "MultiMedia22", "MM_DL22"}, - {"SLIMBUS_6_RX Audio Mixer", "MultiMedia23", "MM_DL23"}, - {"SLIMBUS_6_RX Audio Mixer", "MultiMedia24", "MM_DL24"}, - {"SLIMBUS_6_RX Audio Mixer", "MultiMedia25", "MM_DL25"}, - {"SLIMBUS_6_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Audio Mixer"}, {"SLIMBUS_7_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13163,12 +12828,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_7_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SLIMBUS_7_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SLIMBUS_7_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SLIMBUS_7_RX Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"SLIMBUS_7_RX Audio Mixer", "MultiMedia22", "MM_DL22"}, - {"SLIMBUS_7_RX Audio Mixer", "MultiMedia23", "MM_DL23"}, - {"SLIMBUS_7_RX Audio Mixer", "MultiMedia24", "MM_DL24"}, - {"SLIMBUS_7_RX Audio Mixer", "MultiMedia25", "MM_DL25"}, - {"SLIMBUS_7_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SLIMBUS_7_RX", NULL, "SLIMBUS_7_RX Audio Mixer"}, {"USB_AUDIO_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13187,7 +12846,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"USB_AUDIO_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"USB_AUDIO_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"USB_AUDIO_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"USB_AUDIO_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"USB_AUDIO_RX", NULL, "USB_AUDIO_RX Audio Mixer"}, {"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"}, @@ -13217,7 +12875,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, - {"MultiMedia16 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia5 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"}, {"MultiMedia5 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13236,7 +12893,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"MI2S_RX", NULL, "MI2S_RX Audio Mixer"}, {"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13254,7 +12910,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"QUAT_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"QUAT_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"}, {"TERT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13271,7 +12926,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"TERT_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Audio Mixer"}, {"SEC_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13288,7 +12942,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SEC_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Audio Mixer"}, {"SEC_MI2S_RX_SD1 Audio Mixer", "MultiMedia6", "MM_DL6"}, @@ -13312,7 +12965,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"PRI_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"}, {"INT0_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13330,7 +12982,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"INT0_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"INT0_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"INT0_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"INT0_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"INT0_MI2S_RX", NULL, "INT0_MI2S_RX Audio Mixer"}, {"INT4_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13348,7 +12999,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"INT4_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"INT4_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"INT4_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"INT4_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX Audio Mixer"}, {"QUIN_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13368,7 +13018,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUIN_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"QUIN_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUIN_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"QUIN_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX Audio Mixer"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13387,8 +13036,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"}, {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13407,8 +13054,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1 Audio Mixer"}, {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13427,8 +13072,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2 Audio Mixer"}, {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13447,8 +13090,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3 Audio Mixer"}, {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13485,8 +13126,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"}, {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13505,8 +13144,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1 Audio Mixer"}, {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13525,8 +13162,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2 Audio Mixer"}, {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13545,8 +13180,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3 Audio Mixer"}, {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13583,8 +13216,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0 Audio Mixer"}, {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13621,8 +13252,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_1 Audio Mixer"}, {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13641,8 +13270,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_2 Audio Mixer"}, {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13661,8 +13288,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Audio Mixer"}, {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13681,8 +13306,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"TERT_TDM_RX_4", NULL, "TERT_TDM_RX_4 Audio Mixer"}, {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13702,8 +13325,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia20", "MM_DL20"}, - {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13722,7 +13343,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13741,7 +13361,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"}, {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13779,8 +13398,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"}, {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia20", "MM_DL20"}, - {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1 Audio Mixer"}, {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13800,8 +13417,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"}, {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia20", "MM_DL20"}, - {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2 Audio Mixer"}, {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -13821,8 +13436,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"}, {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"}, {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia20", "MM_DL20"}, - {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia26", "MM_DL26"}, {"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Audio Mixer"}, {"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"}, @@ -13830,11 +13443,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"}, {"MultiMedia3 Mixer", "MI2S_TX", "MI2S_TX"}, {"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"}, - {"MultiMedia16 Mixer", "MI2S_TX", "MI2S_TX"}, {"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"MultiMedia2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"MultiMedia6 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, - {"MultiMedia27 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"MultiMedia1 Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX"}, {"MultiMedia2 Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX"}, {"MultiMedia1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, @@ -13844,29 +13455,24 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia1 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia2 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, - {"MultiMedia27 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"MultiMedia3 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"}, {"MultiMedia5 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, {"MultiMedia3 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"}, - {"MultiMedia16 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"}, - {"MultiMedia16 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"}, {"MultiMedia1 Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"}, {"MultiMedia3 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"}, {"MultiMedia1 Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia3 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, - {"MultiMedia16 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia2 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"}, {"MultiMedia2 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"}, {"MultiMedia2 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, - {"MultiMedia27 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia2 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia6 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"MultiMedia6 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, @@ -13875,11 +13481,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia6 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"}, {"MultiMedia3 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"}, {"MultiMedia5 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"}, - {"MultiMedia16 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"}, {"MultiMedia6 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia3 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia5 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, - {"MultiMedia16 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"}, {"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"MultiMedia6 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, @@ -14034,25 +13638,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia20 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, {"MultiMedia20 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, - {"MultiMedia21 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, - {"MultiMedia21 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, - {"MultiMedia21 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, - {"MultiMedia21 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, - {"MultiMedia21 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"}, - {"MultiMedia21 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"}, - {"MultiMedia21 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"}, - {"MultiMedia21 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"}, - {"MultiMedia21 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, - {"MultiMedia21 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, - {"MultiMedia21 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, - {"MultiMedia21 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"}, - {"MultiMedia21 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"}, - {"MultiMedia21 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"}, - {"MultiMedia21 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, - {"MultiMedia21 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, - {"MultiMedia21 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, - {"MultiMedia21 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, - {"MultiMedia1 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, {"MultiMedia2 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, {"MultiMedia4 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, @@ -14060,24 +13645,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia6 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, {"MultiMedia8 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, - {"MultiMedia16 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, - {"MultiMedia16 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, - {"MultiMedia16 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, - {"MultiMedia16 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, - {"MultiMedia16 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"}, - {"MultiMedia16 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"}, - {"MultiMedia16 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"}, - {"MultiMedia16 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"}, - {"MultiMedia16 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, - {"MultiMedia16 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, - {"MultiMedia16 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, - {"MultiMedia16 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"}, - {"MultiMedia16 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"}, - {"MultiMedia16 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"}, - {"MultiMedia16 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, - {"MultiMedia16 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, - {"MultiMedia16 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, - {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, @@ -14160,10 +13727,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, - {"MultiMedia16 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"}, {"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, - {"MultiMedia16 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia17 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia18 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MultiMedia19 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, @@ -14179,7 +13744,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"}, - {"MultiMedia16 Mixer", "AFE_PCM_TX", "PCM_TX"}, {"MM_UL1", NULL, "MultiMedia1 Mixer"}, {"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"MM_UL2", NULL, "MultiMedia2 Mixer"}, @@ -14189,13 +13753,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"MM_UL6", NULL, "MultiMedia6 Mixer"}, {"MM_UL8", NULL, "MultiMedia8 Mixer"}, {"MM_UL9", NULL, "MultiMedia9 Mixer"}, - {"MM_UL16", NULL, "MultiMedia16 Mixer"}, {"MM_UL17", NULL, "MultiMedia17 Mixer"}, {"MM_UL18", NULL, "MultiMedia18 Mixer"}, {"MM_UL19", NULL, "MultiMedia19 Mixer"}, {"MM_UL20", NULL, "MultiMedia20 Mixer"}, - {"MM_UL21", NULL, "MultiMedia21 Mixer"}, - {"MM_UL27", NULL, "MultiMedia27 Mixer"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, @@ -14213,9 +13774,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_UL6"}, - {"AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_UL21"}, {"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"}, {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -14234,9 +13792,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_DL21"}, - {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_UL6"}, - {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia21", "MM_UL21"}, {"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX Audio Mixer"}, {"TERT_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -14608,7 +14163,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"}, {"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"}, {"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"}, - {"MM_UL16", NULL, "AUDIO_REF_EC_UL16 MUX"}, {"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"}, {"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"}, {"MM_UL19", NULL, "AUDIO_REF_EC_UL19 MUX"}, @@ -15141,10 +14695,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_0 Port Mixer", "AFE_PCM_TX", "PCM_TX"}, {"QUAT_TDM_RX_0 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"QUAT_TDM_RX_0 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, - {"QUAT_TDM_RX_0 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, - {"QUAT_TDM_RX_0 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, - {"QUAT_TDM_RX_0 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, - {"QUAT_TDM_RX_0 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"QUAT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, {"QUAT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, {"QUAT_TDM_RX_0 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, @@ -15163,10 +14713,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_1 Port Mixer", "AFE_PCM_TX", "PCM_TX"}, {"QUAT_TDM_RX_1 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"QUAT_TDM_RX_1 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, - {"QUAT_TDM_RX_1 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, - {"QUAT_TDM_RX_1 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, - {"QUAT_TDM_RX_1 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, - {"QUAT_TDM_RX_1 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"QUAT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, {"QUAT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, {"QUAT_TDM_RX_1 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, @@ -15185,10 +14731,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_2 Port Mixer", "AFE_PCM_TX", "PCM_TX"}, {"QUAT_TDM_RX_2 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"QUAT_TDM_RX_2 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, - {"QUAT_TDM_RX_2 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, - {"QUAT_TDM_RX_2 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, - {"QUAT_TDM_RX_2 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, - {"QUAT_TDM_RX_2 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"QUAT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, {"QUAT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, {"QUAT_TDM_RX_2 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, @@ -15207,10 +14749,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUAT_TDM_RX_3 Port Mixer", "AFE_PCM_TX", "PCM_TX"}, {"QUAT_TDM_RX_3 Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"QUAT_TDM_RX_3 Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, - {"QUAT_TDM_RX_3 Port Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, - {"QUAT_TDM_RX_3 Port Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, - {"QUAT_TDM_RX_3 Port Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"}, - {"QUAT_TDM_RX_3 Port Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"}, {"QUAT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, {"QUAT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, {"QUAT_TDM_RX_3 Port Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, @@ -15659,6 +15197,10 @@ static int msm_pcm_routing_close(struct snd_pcm_substream *substream) bedai->active = 0; bedai->sample_rate = 0; bedai->channel = 0; + for (i = 0; i < MSM_FRONTEND_DAI_MAX; i++) { + if (bedai->passthr_mode[i] != LISTEN) + bedai->passthr_mode[i] = LEGACY_PCM; + } mutex_unlock(&routing_lock); return 0; @@ -15861,7 +15403,7 @@ done: static int msm_routing_send_device_pp_params(int port_id, int copp_idx, int fe_id) { - int topo_id, be_idx; + int index, topo_id, be_idx; unsigned long pp_config = 0; bool mute_on; int latency; @@ -15885,6 +15427,16 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx, return -EINVAL; } + for (index = 0; index < MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX; index++) { + if (msm_bedais_pp_params[index].port_id == port_id) + break; + } + if (index >= MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX) { + pr_err("%s: Invalid backend pp params index %d\n", + __func__, index); + return -EINVAL; + } + topo_id = adm_get_topology_for_port_copp_idx(port_id, copp_idx); if (topo_id != COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY) { pr_err("%s: Invalid passthrough topology 0x%x\n", @@ -15896,11 +15448,11 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx, (msm_bedais[be_idx].passthr_mode[fe_id] == LISTEN)) compr_passthr_mode = false; - pp_config = msm_bedais_pp_params[be_idx].pp_params_config; + pp_config = msm_bedais_pp_params[index].pp_params_config; if (test_bit(ADM_PP_PARAM_MUTE_BIT, &pp_config)) { pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__); clear_bit(ADM_PP_PARAM_MUTE_BIT, &pp_config); - mute_on = msm_bedais_pp_params[be_idx].mute_on; + mute_on = msm_bedais_pp_params[index].mute_on; if ((msm_bedais[be_idx].active) && compr_passthr_mode) adm_send_compressed_device_mute(port_id, copp_idx, @@ -15910,7 +15462,7 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx, pr_debug("%s: ADM_PP_PARAM_LATENCY\n", __func__); clear_bit(ADM_PP_PARAM_LATENCY_BIT, &pp_config); - latency = msm_bedais_pp_params[be_idx].latency; + latency = msm_bedais_pp_params[index].latency; if ((msm_bedais[be_idx].active) && compr_passthr_mode) adm_send_compressed_device_latency(port_id, copp_idx, @@ -15919,47 +15471,18 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx, return 0; } -static bool msm_pcm_routing_test_pp_param(int be_idx, long param_bit) -{ - return test_bit(param_bit, - &msm_bedais_pp_params[be_idx].pp_params_config); -} - -static void msm_routing_set_pp_param(long param_bit, int value) -{ - int be_idx; - - if (value) { - for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) - set_bit(param_bit, - &msm_bedais_pp_params[be_idx]. - pp_params_config); - } else { - for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) - clear_bit(param_bit, - &msm_bedais_pp_params[be_idx]. - pp_params_config); - } -} - static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int pp_id = ucontrol->value.integer.value[0]; - int value = ucontrol->value.integer.value[1]; int port_id = 0; - int be_idx, i, topo_id, idx; + int index, be_idx, i, topo_id, idx; bool mute; int latency; bool compr_passthr_mode = true; pr_debug("%s: pp_id: 0x%x\n", __func__, pp_id); - if (pp_id == ADM_PP_PARAM_LIMITER_ID) { - msm_routing_set_pp_param(ADM_PP_PARAM_LIMITER_BIT, value); - goto done; - } - for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++) { port_id = msm_bedais[be_idx].port_id; if (port_id == HDMI_RX || port_id == DISPLAY_PORT_RX) @@ -15971,6 +15494,16 @@ static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol, return -EINVAL; } + for (index = 0; index < MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX; index++) { + if (msm_bedais_pp_params[index].port_id == port_id) + break; + } + if (index >= MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX) { + pr_err("%s: Invalid pp params backend index %d\n", + __func__, index); + return -EINVAL; + } + for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions[0], MSM_FRONTEND_DAI_MM_SIZE) { if ((msm_bedais[be_idx].passthr_mode[i] == LEGACY_PCM) || @@ -15993,20 +15526,22 @@ static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol, switch (pp_id) { case ADM_PP_PARAM_MUTE_ID: pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__); - mute = value ? true : false; - msm_bedais_pp_params[be_idx].mute_on = mute; + mute = ucontrol->value.integer.value[1] ? true : false; + msm_bedais_pp_params[index].mute_on = mute; set_bit(ADM_PP_PARAM_MUTE_BIT, - &msm_bedais_pp_params[be_idx].pp_params_config); + &msm_bedais_pp_params[index].pp_params_config); if ((msm_bedais[be_idx].active) && compr_passthr_mode) adm_send_compressed_device_mute(port_id, idx, mute); break; case ADM_PP_PARAM_LATENCY_ID: pr_debug("%s: ADM_PP_PARAM_LATENCY\n", __func__); - msm_bedais_pp_params[be_idx].latency = value; + msm_bedais_pp_params[index].latency = + ucontrol->value.integer.value[1]; set_bit(ADM_PP_PARAM_LATENCY_BIT, - &msm_bedais_pp_params[be_idx].pp_params_config); - latency = msm_bedais_pp_params[be_idx].latency = value; + &msm_bedais_pp_params[index].pp_params_config); + latency = msm_bedais_pp_params[index].latency = + ucontrol->value.integer.value[1]; if ((msm_bedais[be_idx].active) && compr_passthr_mode) adm_send_compressed_device_latency(port_id, idx, latency); @@ -16018,7 +15553,6 @@ static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol, } } } -done: return 0; } @@ -16187,96 +15721,6 @@ static struct snd_pcm_ops msm_routing_pcm_ops = { .prepare = msm_pcm_routing_prepare, }; -int msm_routing_set_downmix_control_data(int be_id, int session_id, - struct asm_stream_pan_ctrl_params *dnmix_param) -{ - int i, rc = 0; - struct adm_pspd_param_data_t data; - struct audproc_chmixer_param_coeff dnmix_cfg; - uint16_t variable_payload = 0; - char *adm_params = NULL; - int port_id, copp_idx = 0; - uint32_t params_length = 0; - uint16_t ii; - uint16_t *dst_gain_ptr = NULL; - - if (be_id >= MSM_BACKEND_DAI_MAX) { - rc = -EINVAL; - return rc; - } - port_id = msm_bedais[be_id].port_id; - copp_idx = adm_get_default_copp_idx(port_id); - pr_debug("%s: port_id - %d, copp_idx %d session id - %d\n", - __func__, port_id, copp_idx, session_id); - - variable_payload = dnmix_param->num_output_channels * sizeof(uint16_t)+ - dnmix_param->num_input_channels * sizeof(uint16_t) + - dnmix_param->num_output_channels * - dnmix_param->num_input_channels * sizeof(uint16_t); - i = (variable_payload % sizeof(uint32_t)); - variable_payload += (i == 0) ? 0 : sizeof(uint32_t) - i; - - params_length = variable_payload + - sizeof(struct adm_pspd_param_data_t) + - sizeof(struct audproc_chmixer_param_coeff); - adm_params = kzalloc(params_length, GFP_KERNEL); - if (!adm_params) { - rc = -ENOMEM; - goto end; - } - - data.module_id = AUDPROC_MODULE_ID_CHMIXER; - data.param_id = AUDPROC_CHMIXER_PARAM_ID_COEFF; - data.param_size = sizeof(struct audproc_chmixer_param_coeff) + - variable_payload; - data.reserved = 0; - memcpy((u8 *)adm_params, &data, sizeof(struct adm_pspd_param_data_t)); - - dnmix_cfg.index = 0; - dnmix_cfg.num_output_channels = dnmix_param->num_output_channels; - dnmix_cfg.num_input_channels = dnmix_param->num_input_channels; - memcpy(((u8 *)adm_params + - sizeof(struct adm_pspd_param_data_t)), - &dnmix_cfg, sizeof(struct audproc_chmixer_param_coeff)); - - memcpy(((u8 *)adm_params + - sizeof(struct adm_pspd_param_data_t) + - sizeof(struct audproc_chmixer_param_coeff)), - dnmix_param->output_channel_map, - dnmix_param->num_output_channels * sizeof(uint16_t)); - memcpy(((u8 *)adm_params + - sizeof(struct adm_pspd_param_data_t) + - sizeof(struct audproc_chmixer_param_coeff) + - dnmix_param->num_output_channels * sizeof(uint16_t)), - dnmix_param->input_channel_map, - dnmix_param->num_input_channels * sizeof(uint16_t)); - - dst_gain_ptr = (uint16_t *) ((u8 *)adm_params + - sizeof(struct adm_pspd_param_data_t) + - sizeof(struct audproc_chmixer_param_coeff) + - (dnmix_param->num_output_channels * sizeof(uint16_t)) + - (dnmix_param->num_input_channels * sizeof(uint16_t))); - for (ii = 0; ii < dnmix_param->num_output_channels * - dnmix_param->num_input_channels; ii++) - dst_gain_ptr[ii] = (uint16_t) dnmix_param->gain[ii]; - - if (params_length) { - rc = adm_set_pspd_matrix_params(port_id, - copp_idx, - session_id, - adm_params, - params_length); - if (rc) { - pr_err("%s: send params failed rc=%d\n", __func__, rc); - rc = -EINVAL; - } - } -end: - kfree(adm_params); - return rc; -} - - /* Not used but frame seems to require it */ static int msm_routing_probe(struct snd_soc_platform *platform) { @@ -16312,6 +15756,10 @@ static int msm_routing_probe(struct snd_soc_platform *platform) snd_soc_add_platform_controls(platform, channel_mixer_controls, ARRAY_SIZE(channel_mixer_controls)); + snd_soc_add_platform_controls(platform, + sony_stereo_to_custom_stereo_controls, + ARRAY_SIZE(sony_stereo_to_custom_stereo_controls)); + msm_qti_pp_add_controls(platform); msm_dts_srs_tm_add_controls(platform); @@ -16322,10 +15770,15 @@ static int msm_routing_probe(struct snd_soc_platform *platform) use_ds1_or_ds2_controls, ARRAY_SIZE(use_ds1_or_ds2_controls)); + msm_routing_ahc_add_controls(platform); + snd_soc_add_platform_controls(platform, device_pp_params_mixer_controls, ARRAY_SIZE(device_pp_params_mixer_controls)); + snd_soc_add_platform_controls(platform, msm_adm_mute_controls, + ARRAY_SIZE(msm_adm_mute_controls)); + snd_soc_add_platform_controls(platform, msm_routing_be_dai_name_table_mixer_controls, ARRAY_SIZE(msm_routing_be_dai_name_table_mixer_controls)); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 21dfa48308c380935b9f0ef35e040c02dd2a0c6d..b5a4ee5246d604cd691f65fec38e52d933b7b5e0 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #ifndef _MSM_PCM_ROUTING_H #define _MSM_PCM_ROUTING_H #include @@ -56,8 +61,8 @@ #define LPASS_BE_SEC_MI2S_TX "SEC_MI2S_TX" #define LPASS_BE_PRI_MI2S_RX "PRI_MI2S_RX" #define LPASS_BE_PRI_MI2S_TX "PRI_MI2S_TX" -#define LPASS_BE_TERT_MI2S_RX "TERT_MI2S_RX" -#define LPASS_BE_TERT_MI2S_TX "TERT_MI2S_TX" +#define LPASS_BE_TERT_MI2S_RX "TERTIARY_MI2S_RX" +#define LPASS_BE_TERT_MI2S_TX "TERTIARY_MI2S_TX" #define LPASS_BE_AUDIO_I2S_RX "AUDIO_I2S_RX" #define LPASS_BE_STUB_RX "STUB_RX" #define LPASS_BE_STUB_TX "STUB_TX" @@ -193,13 +198,6 @@ enum { MSM_FRONTEND_DAI_MULTIMEDIA18, MSM_FRONTEND_DAI_MULTIMEDIA19, MSM_FRONTEND_DAI_MULTIMEDIA20, - MSM_FRONTEND_DAI_MULTIMEDIA21, - MSM_FRONTEND_DAI_MULTIMEDIA22, - MSM_FRONTEND_DAI_MULTIMEDIA23, - MSM_FRONTEND_DAI_MULTIMEDIA24, - MSM_FRONTEND_DAI_MULTIMEDIA25, - MSM_FRONTEND_DAI_MULTIMEDIA26, - MSM_FRONTEND_DAI_MULTIMEDIA27, MSM_FRONTEND_DAI_CS_VOICE, MSM_FRONTEND_DAI_VOIP, MSM_FRONTEND_DAI_AFE_RX, @@ -225,8 +223,8 @@ enum { MSM_FRONTEND_DAI_MAX, }; -#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA27 + 1) -#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA27 +#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA20 + 1) +#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA20 enum { MSM_BACKEND_DAI_PRI_I2S_RX = 0, @@ -389,6 +387,13 @@ enum { EXT_EC_REF_SLIM_1_TX, }; +enum { + SONY_CUSTOM_STEREO_NORMAL = 0, + SONY_CUSTOM_STEREO_MIX, + SONY_CUSTOM_STEREO_SWAP, + SONY_CUSTOM_STEREO_MAX, +}; + #define INVALID_SESSION -1 #define SESSION_TYPE_RX 0 #define SESSION_TYPE_TX 1 @@ -399,20 +404,12 @@ enum { #define RELEASE_LOCK 0 #define ACQUIRE_LOCK 1 +#define MSM_BACKEND_DAI_PP_PARAMS_REQ_MAX 2 #define HDMI_RX_ID 0x8001 - -enum { - ADM_PP_PARAM_MUTE_ID, - ADM_PP_PARAM_LATENCY_ID, - ADM_PP_PARAM_LIMITER_ID -}; - -enum { - ADM_PP_PARAM_MUTE_BIT = 0x1, - ADM_PP_PARAM_LATENCY_BIT = 0x2, - ADM_PP_PARAM_LIMITER_BIT = 0x4 -}; - +#define ADM_PP_PARAM_MUTE_ID 0 +#define ADM_PP_PARAM_MUTE_BIT 1 +#define ADM_PP_PARAM_LATENCY_ID 1 +#define ADM_PP_PARAM_LATENCY_BIT 2 #define BE_DAI_PORT_SESSIONS_IDX_MAX 4 #define BE_DAI_FE_SESSIONS_IDX_MAX 2 @@ -498,6 +495,4 @@ int msm_pcm_routing_reg_stream_app_type_cfg( int msm_pcm_routing_get_stream_app_type_cfg( int fedai_id, int session_type, int *be_id, struct msm_pcm_stream_app_type_cfg *cfg_data); -int msm_routing_set_downmix_control_data(int be_id, int session_id, - struct asm_stream_pan_ctrl_params *pan_param); #endif /*_MSM_PCM_H*/ diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index 65f5167d9dee8d859a3a05d53e713f55c1d2ea67..cac28f43e5ae371f9aeaa61302992abc252c3765 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -298,11 +298,11 @@ int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, int copp_idx, *update_params_value16++ = op_FR_ip_FR_weight; avail_length = avail_length - (4 * sizeof(uint16_t)); if (params_length) { - rc = adm_set_pspd_matrix_params(port_id, - copp_idx, - session_id, - params_value, - params_length); + rc = adm_set_stereo_to_custom_stereo(port_id, + copp_idx, + session_id, + params_value, + params_length); if (rc) { pr_err("%s: send params failed rc=%d\n", __func__, rc); kfree(params_value); diff --git a/sound/soc/msm/qdsp6v2/msm-sony-hweffect.c b/sound/soc/msm/qdsp6v2/msm-sony-hweffect.c new file mode 100644 index 0000000000000000000000000000000000000000..8f0ae5d00eaaf7f51c97c7e294d434aca803ec89 --- /dev/null +++ b/sound/soc/msm/qdsp6v2/msm-sony-hweffect.c @@ -0,0 +1,529 @@ +/* + * Author: Yoshio Yamamoto yoshio.xa.yamamoto@sonymobile.com + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include "msm-sony-hweffect.h" +#include "sound/sony-hweffect-params.h" + +#define MAX_SUPPORTED_SAMPLERATE 48000 +#define MAX_SUPPORTED_BITWIDTH 16 +#define MAX_SUPPORTED_CHANNEL_COUNT 2 + +struct mfc_output_media_fmt { + uint32_t sampling_rate; + uint16_t bits_per_sample; + uint16_t num_channels; + uint16_t channel_type[8]; +} __packed; + +static void set_mfc_output_format(struct mfc_output_media_fmt *mfc_params, + uint32_t sampling_rate, + uint16_t bits_per_sample, + uint16_t num_channels) +{ + mfc_params->sampling_rate = sampling_rate; + mfc_params->bits_per_sample = bits_per_sample; + mfc_params->num_channels = num_channels; + if (num_channels == 1) { + mfc_params->channel_type[0] = PCM_CHANNEL_FC; + } else if (num_channels == 2) { + mfc_params->channel_type[0] = PCM_CHANNEL_FL; + mfc_params->channel_type[1] = PCM_CHANNEL_FR; + } else if (num_channels == 3) { + mfc_params->channel_type[0] = PCM_CHANNEL_FL; + mfc_params->channel_type[1] = PCM_CHANNEL_FR; + mfc_params->channel_type[2] = PCM_CHANNEL_FC; + } else if (num_channels == 4) { + mfc_params->channel_type[0] = PCM_CHANNEL_FL; + mfc_params->channel_type[1] = PCM_CHANNEL_FR; + mfc_params->channel_type[2] = PCM_CHANNEL_LS; + mfc_params->channel_type[3] = PCM_CHANNEL_RS; + } else if (num_channels == 5) { + mfc_params->channel_type[0] = PCM_CHANNEL_FL; + mfc_params->channel_type[1] = PCM_CHANNEL_FR; + mfc_params->channel_type[2] = PCM_CHANNEL_FC; + mfc_params->channel_type[3] = PCM_CHANNEL_LS; + mfc_params->channel_type[4] = PCM_CHANNEL_RS; + } else if (num_channels == 6) { + mfc_params->channel_type[0] = PCM_CHANNEL_FL; + mfc_params->channel_type[1] = PCM_CHANNEL_FR; + mfc_params->channel_type[2] = PCM_CHANNEL_LFE; + mfc_params->channel_type[3] = PCM_CHANNEL_FC; + mfc_params->channel_type[4] = PCM_CHANNEL_LS; + mfc_params->channel_type[5] = PCM_CHANNEL_RS; + } else if (num_channels == 7) { + mfc_params->channel_type[0] = PCM_CHANNEL_FL; + mfc_params->channel_type[1] = PCM_CHANNEL_FR; + mfc_params->channel_type[2] = PCM_CHANNEL_FC; + mfc_params->channel_type[3] = PCM_CHANNEL_LFE; + mfc_params->channel_type[4] = PCM_CHANNEL_LB; + mfc_params->channel_type[5] = PCM_CHANNEL_RB; + mfc_params->channel_type[6] = PCM_CHANNEL_CS; + } else if (num_channels == 8) { + mfc_params->channel_type[0] = PCM_CHANNEL_FL; + mfc_params->channel_type[1] = PCM_CHANNEL_FR; + mfc_params->channel_type[2] = PCM_CHANNEL_LFE; + mfc_params->channel_type[3] = PCM_CHANNEL_FC; + mfc_params->channel_type[4] = PCM_CHANNEL_LS; + mfc_params->channel_type[5] = PCM_CHANNEL_RS; + mfc_params->channel_type[6] = PCM_CHANNEL_LB; + mfc_params->channel_type[7] = PCM_CHANNEL_RB; + } else { + pr_err("%s: invalid num_channels %d\n", __func__, + num_channels); + /* Fallback for unexpected channels. */ + mfc_params->num_channels = 2; + mfc_params->channel_type[0] = PCM_CHANNEL_FL; + mfc_params->channel_type[1] = PCM_CHANNEL_FR; + } + + pr_debug("%s: sampling_rate:%d, bits_per_sample:%d, num_channels:%d\n", + __func__, mfc_params->sampling_rate, + mfc_params->bits_per_sample, mfc_params->num_channels); + + return; +} + +/* + * Value array (max size:128) + * +---------------+---------------------------+ + * | array index | value | + * +---------------+---------------------------+ + * | 0 | output device (unused) | + * +---------------+---------------------------+ + * | 1 | num of commands | + * +---------------+---------------------------+ + * | 2 | 1st command | + * +---------------+---------------------------+ + * | 3 | config state | + * +---------------+---------------------------+ + * | 4 | 1st param offset | + * +---------------+---------------------------+ + * | 5 | 1st param length | + * +---------------+---------------------------+ + * | 6 to n | 1st param effect params | + * +---------------+---------------------------+ + * | n + 1 | 2nd command | + * +---------------+---------------------------+ + * | n + 2 | config state | + * +---------------+---------------------------+ + * | n + 3 | 2nd param offset | + * +---------------+---------------------------+ + * | n + 4 | 2nd param length | + * +---------------+---------------------------+ + * | (n + 5) to m | 2nd param effect params | + * +---------------+---------------------------+ + * . + * . + * . +*/ + +int msm_sony_hweffect_sonybundle_handler(struct audio_client *ac, + struct sonybundle_params *sb, + long *values, + uint32_t sampling_rate, + uint16_t bits_per_sample, + uint16_t num_channels) +{ + int devices = *values++; + int num_commands = *values++; + char *params, *effect; + int i, j; + uint32_t module_id, param_id; + int rc = 0; + + pr_debug("%s\n", __func__); + if (!ac) { + pr_err("%s: cannot set sonyeffect hw\n", __func__); + return -EINVAL; + } + params = kzalloc(MAX_INBAND_PARAM_SZ, GFP_KERNEL); + if (!params) { + pr_err("%s, params memory alloc failed\n", __func__); + return -ENOMEM; + } + pr_debug("%s: device: %d, num_commands %d\n", + __func__, devices, num_commands); + + effect = params + sizeof(struct asm_stream_param_data_v2); + for (i = 0; i < num_commands; i++) { + uint32_t p_length = 0; + uint32_t command_id = *values++; + uint32_t command_config_state = *values++; + uint32_t index_offset = *values++; + uint32_t length = *values++; + switch (command_id) { + case SONYBUNDLE_ENABLE: + if (length != 1 || index_offset != 0) { + pr_err("SONYBUNDLE_ENABLE:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->common.enable_flag = *values++; + pr_debug("%s:SONYBUNDLE_ENABLE state:%d\n", __func__, + sb->common.enable_flag); + if (command_config_state == CONFIG_SET) { + struct common_params *cmn_params = + (struct common_params *)effect; + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_COMMON_USER_PARAM; + cmn_params->enable_flag = + sb->common.enable_flag; + p_length += sizeof(struct common_params); + } + break; + + case DYNAMIC_NORMALIZER_ENABLE: + if (length != 1 || index_offset != 0) { + pr_err("DYNAMIC_NORMALIZER_ENABLE:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->dynamic_normalizer.enable_flag = *values++; + pr_debug("%s:DYNAMIC_NORMALIZER_ENABLE state:%d\n", + __func__, sb->dynamic_normalizer.enable_flag); + if (command_config_state == CONFIG_SET) { + struct dynamic_normalizer_params *dn_params = + (struct dynamic_normalizer_params *)effect; + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = + PARAM_ID_SB_DYNAMICNORMALIZER_USER_PARAM; + dn_params->enable_flag = + sb->dynamic_normalizer.enable_flag; + p_length += + sizeof(struct dynamic_normalizer_params); + } + break; + + case SFORCE_ENABLE: + if (length != 1 || index_offset != 0) { + pr_err("SFORCE_ENABLE:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->sforce.enable_flag = *values++; + pr_debug("%s:SFORCE_ENABLE state:%d\n", __func__, + sb->sforce.enable_flag); + if (command_config_state == CONFIG_SET) { + struct sforce_params *sf_params = + (struct sforce_params *)effect; + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_SFORCE_USER_PARAM; + sf_params->enable_flag = + sb->sforce.enable_flag; + p_length += sizeof(struct sforce_params); + + if (!sb->sforce_tuning_update) { + int ret; + ret = sony_hweffect_send_tuning_params( + SFORCE_PARAM, + (void *)ac); + pr_debug("%s:sony_hweffect_send_tuning_params(S-Force) ret=%d\n", + __func__, ret); + if (ret < 0) { + pr_err("SFORCE_ENABLE: send tuning param error\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->sforce_tuning_update = true; + } + } + break; + + case VPT20_MODE: + if (length != 1 || index_offset != 0) { + pr_err("VPT20_MODE:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->vpt20.mode = *values++; + pr_debug("%s:VPT20_MODE: %d\n", __func__, + sb->vpt20.mode); + if (command_config_state == CONFIG_SET) { + struct vpt20_params *vpt_params = + (struct vpt20_params *)effect; + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_VPT20_USER_PARAM; + vpt_params->mode = sb->vpt20.mode; + p_length += sizeof(struct vpt20_params); + } + break; + + case CLEARPHASE_HP_MODE: + if (length != 1 || index_offset != 0) { + pr_err("CLEARPHASE_HP_MODE:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->clearphase_hp.mode = *values++; + pr_debug("%s:CLEARPHASE_HP_MODE: %d\n", __func__, + sb->clearphase_hp.mode); + if (command_config_state == CONFIG_SET) { + struct clearphase_hp_params *cp_hp_params = + (struct clearphase_hp_params *)effect; + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_CLEARPHASE_HP_USER_PARAM; + cp_hp_params->mode = sb->clearphase_hp.mode; + p_length += sizeof(struct clearphase_hp_params); + + { + int ret; + ret = sony_hweffect_send_tuning_params( + CLEARPHASE_HP_PARAM, + (void *)ac); + pr_debug("%s:sony_hweffect_send_tuning_params(CP_HP) ret=%d\n", + __func__, ret); + if (ret < 0) { + pr_err("CLEARPHASE_HP_MODE: send tuning param error\n"); + rc = -EINVAL; + goto invalid_config; + } + } + } + break; + + case CLEARAUDIO_CHSEP: + if (length != 1 || index_offset != 0) { + pr_err("CLEARAUDIO_CHSEP:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->clearaudio.chsep_coef = *values++; + pr_debug("%s:CLEARAUDIO_CHSEP: %d\n", __func__, + sb->clearaudio.chsep_coef); + if (command_config_state == CONFIG_SET) { + struct clearaudio_params *ca_params = + (struct clearaudio_params *)effect; + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_CLEARAUDIO_USER_PARAM; + ca_params->chsep_coef = + sb->clearaudio.chsep_coef; + for (j = 0; j < BAND_NUM; j++) + ca_params->eq_coef[j] = + sb->clearaudio.eq_coef[j]; + p_length += + sizeof(struct clearaudio_params); + } + break; + + case CLEARAUDIO_EQ_COEF: + if (length != 6 || index_offset != 0) { + pr_err("CLEARAUDIO_EQ_COEF:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + for (j = 0; j < BAND_NUM; j++) + sb->clearaudio.eq_coef[j] = + (int16_t)*values++; + pr_debug("%s:CLEARAUDIO_EQ_COEF: %d %d %d %d %d %d\n", + __func__, + sb->clearaudio.eq_coef[0], + sb->clearaudio.eq_coef[1], + sb->clearaudio.eq_coef[2], + sb->clearaudio.eq_coef[3], + sb->clearaudio.eq_coef[4], + sb->clearaudio.eq_coef[5]); + if (command_config_state == CONFIG_SET) { + struct clearaudio_params *ca_params = + (struct clearaudio_params *)effect; + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_CLEARAUDIO_USER_PARAM; + ca_params->chsep_coef = + sb->clearaudio.chsep_coef; + for (j = 0; j < BAND_NUM; j++) + ca_params->eq_coef[j] = + sb->clearaudio.eq_coef[j]; + p_length += + sizeof(struct clearaudio_params); + } + break; + + case CLEARAUDIO_VOLUME: + if (length != 1 || index_offset != 0) { + pr_err("CLEARAUDIO_VOLUME:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->ca_volume.gain = *values++; + pr_debug("%s:CLEARAUDIO_VOLUME: %d\n", __func__, + sb->ca_volume.gain); + if (command_config_state == CONFIG_SET) { + struct clearaudio_volume *ca_volume = + (struct clearaudio_volume *)effect; + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_CLEARAUDIO_VOLUME_PARAM; + ca_volume->gain = sb->ca_volume.gain; + p_length += + sizeof(struct clearaudio_volume); + } + break; + + case CLEARPHASE_SP_ENABLE: + if (length != 1 || index_offset != 0) { + pr_err("CLEARPHASE_SP_ENABLE:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->clearphase_sp.mode = *values++; + pr_debug("%s:CLEARPHASE_SP_ENABLE mode:%d\n", __func__, + sb->clearphase_sp.mode); + if (command_config_state == CONFIG_SET) { + struct clearphase_sp_params *cp_sp_params = + (struct clearphase_sp_params *)effect; + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_CLEARPHASE_SP_USER_PARAM; + cp_sp_params->mode = sb->clearphase_sp.mode; + p_length += + sizeof(struct clearphase_sp_params); + + if (!sb->clearphase_sp_tuning_update) { + int ret; + ret = sony_hweffect_send_tuning_params( + CLEARPHASE_SP_PARAM, + (void *)ac); + pr_debug("%s:sony_hweffect_send_tuning_params(CP_SP) ret=%d\n", + __func__, ret); + if (ret < 0) { + pr_err("CLEARPHASE_SP_ENABLE: send tuning param error\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->clearphase_sp_tuning_update = true; + } + } + break; + + case XLOUD_ENABLE: + if (length != 1 || index_offset != 0) { + pr_err("XLOUD_ENABLE:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->xloud.enable_flag = *values++; + pr_debug("%s:XLOUD_ENABLE state:%d\n", __func__, + sb->xloud.enable_flag); + if (command_config_state == CONFIG_SET) { + struct xloud_params *xl_params = + (struct xloud_params *)effect; + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_XLOUD_USER_PARAM; + xl_params->enable_flag = sb->xloud.enable_flag; + p_length += sizeof(struct xloud_params); + + if (!sb->xloud_tuning_update) { + int ret; + ret = sony_hweffect_send_tuning_params( + XLOUD_PARAM, + (void *)ac); + pr_debug("%s:sony_hweffect_send_tuning_params(XLOUD) ret=%d\n", + __func__, ret); + if (ret < 0) { + pr_err("XLOUD_ENABLE: send tuning param error\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->xloud_tuning_update = true; + } + } + break; + + case DOWN_CONVERT: + if (length != 1 || index_offset != 0) { + pr_err("DOWN_CONVERT:invalid params\n"); + rc = -EINVAL; + goto invalid_config; + } + sb->down_convert_enable = *values++; + pr_debug("%s:DOWN_CONVERT state:%d\n", __func__, + sb->down_convert_enable); + if (command_config_state == CONFIG_SET) { + struct mfc_output_media_fmt *mfc_params = + (struct mfc_output_media_fmt *)effect; + + module_id = AUDPROC_MODULE_ID_MFC; + param_id = AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT; + if (sb->down_convert_enable == 1) { + /* Convert to supported format. */ + set_mfc_output_format(mfc_params, + MAX_SUPPORTED_SAMPLERATE, + MAX_SUPPORTED_BITWIDTH, + MAX_SUPPORTED_CHANNEL_COUNT); + } else { + /* Specify same as input stream to disable down-convert. */ + set_mfc_output_format(mfc_params, + sampling_rate, + bits_per_sample, + num_channels); + } + p_length += sizeof(struct mfc_output_media_fmt); + } + break; + + default: + pr_err("%s: Invalid command to set config\n", __func__); + break; + } + + if (p_length) { + struct asm_stream_param_data_v2 *param_data; + int ret; + + param_data = + (struct asm_stream_param_data_v2 *)params; + param_data->module_id = module_id; + param_data->param_id = param_id; + param_data->param_size = (uint16_t)p_length; + param_data->reserved = 0; + p_length += + sizeof(struct asm_stream_param_data_v2); + + ret = q6asm_send_audio_effects_params(ac, + params, p_length); + if (ret < 0) { + pr_err("q6asm_send_audio_effects_params " + "failed %d\n", ret); + rc = -EINVAL; + goto invalid_config; + } + } + } + +invalid_config: + kfree(params); + return rc; +} + +void init_sonybundle_params(struct sonybundle_params *sb) +{ + /* Initialization of effect having initial value except for 0 */ + sb->clearphase_hp.mode = CP_MODE_OFF; + sb->clearphase_sp.mode = CP_MODE_OFF; + sb->vpt20.mode = VPT_MODE_OFF; + + return; +} diff --git a/sound/soc/msm/qdsp6v2/msm-sony-hweffect.h b/sound/soc/msm/qdsp6v2/msm-sony-hweffect.h new file mode 100644 index 0000000000000000000000000000000000000000..fce427d892658e07106b76dd758db0c114b8bf22 --- /dev/null +++ b/sound/soc/msm/qdsp6v2/msm-sony-hweffect.h @@ -0,0 +1,35 @@ +/* + * Author: Yoshio Yamamoto yoshio.xa.yamamoto@sonymobile.com + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#ifndef _MSM_SONY_HWEFFECT_H +#define _MSM_SONY_HWEFFECT_H + +#include + +#define CP_MODE_1 0 +#define CP_MODE_OFF 4 +#define VPT_MODE_OFF 4 + +int msm_sony_hweffect_sonybundle_handler(struct audio_client *ac, + struct sonybundle_params *sb, + long *values, + uint32_t sampling_rate, + uint16_t bits_per_sample, + uint16_t num_channels); + +void init_sonybundle_params(struct sonybundle_params *sb); + +#endif /*_MSM_SONYEFFECT_HW_H*/ diff --git a/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c index 18cac342405472b540e93b8110252e72c4b3eb16..6bb85ca8e84eb21a00742d5c26518c9898d72eed 100644 --- a/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c @@ -27,8 +27,6 @@ #include #include #include -#include -#include #include #include #include @@ -42,21 +40,11 @@ #include "msm-qti-pp-config.h" #define LOOPBACK_SESSION_MAX_NUM_STREAMS 2 -/* Max volume corresponding to 24dB */ -#define TRANSCODE_LR_VOL_MAX_STEPS 0xFFFF - -#define APP_TYPE_CONFIG_IDX_APP_TYPE 0 -#define APP_TYPE_CONFIG_IDX_ACDB_ID 1 -#define APP_TYPE_CONFIG_IDX_SAMPLE_RATE 2 -#define APP_TYPE_CONFIG_IDX_BE_ID 3 static DEFINE_MUTEX(transcode_loopback_session_lock); struct trans_loopback_pdata { struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX]; - int32_t ion_fd[MSM_FRONTEND_DAI_MAX]; - uint32_t master_gain; - int perf_mode; }; struct loopback_stream { @@ -91,11 +79,6 @@ struct msm_transcode_loopback { int session_id; struct audio_client *audio_client; - int32_t shm_ion_fd; - struct ion_client *lib_ion_client; - struct ion_client *shm_ion_client; - struct ion_handle *lib_ion_handle; - struct ion_handle *shm_ion_handle; }; /* Transcode loopback global info struct */ @@ -117,7 +100,7 @@ static void loopback_event_handler(uint32_t opcode, return; } - cstream = trans->sink.cstream; + cstream = trans->source.cstream; ac = trans->audio_client; /* @@ -196,65 +179,6 @@ static void populate_codec_list(struct msm_transcode_loopback *trans, } } -static int msm_transcode_map_ion_fd(struct msm_transcode_loopback *trans, - int fd) -{ - ion_phys_addr_t paddr; - size_t pa_len = 0; - int ret = 0; - - ret = msm_audio_ion_phys_assign("audio_lib_mem_client", - &trans->lib_ion_client, - &trans->lib_ion_handle, fd, - &paddr, &pa_len, HLOS_TO_ADSP); - if (ret) { - pr_err("%s: audio lib ION phys failed, rc = %d\n", __func__, - ret); - goto done; - } - - ret = q6core_add_remove_pool_pages(paddr, pa_len, - ADSP_MEMORY_MAP_HLOS_PHYSPOOL, true); - if (ret) { - pr_err("%s: add pages failed, rc = %d\n", __func__, ret); - /* Assign back to HLOS if add pages cmd failed */ - msm_audio_ion_phys_free(trans->lib_ion_client, - trans->lib_ion_handle, - &paddr, &pa_len, ADSP_TO_HLOS); - } - -done: - return ret; -} - -static int msm_transcode_unmap_ion_fd(struct msm_transcode_loopback *trans) -{ - ion_phys_addr_t paddr; - size_t pa_len = 0; - int ret = 0; - - if (!trans->lib_ion_client || !trans->lib_ion_handle) { - pr_err("%s: ion_client or ion_handle is NULL", __func__); - return -EINVAL; - } - ret = msm_audio_ion_phys_free(trans->lib_ion_client, - trans->lib_ion_handle, - &paddr, &pa_len, ADSP_TO_HLOS); - if (ret) { - pr_err("%s: audio lib ION phys failed, rc = %d\n", __func__, - ret); - goto done; - } - - ret = q6core_add_remove_pool_pages(paddr, pa_len, - ADSP_MEMORY_MAP_HLOS_PHYSPOOL, false); - if (ret) - pr_err("%s: remove pages failed, rc = %d\n", __func__, ret); - -done: - return ret; -} - static int msm_transcode_loopback_open(struct snd_compr_stream *cstream) { int ret = 0; @@ -299,13 +223,6 @@ static int msm_transcode_loopback_open(struct snd_compr_stream *cstream) ret = -EINVAL; goto exit; } - msm_adsp_init_mixer_ctl_pp_event_queue(rtd); - if (pdata->ion_fd[rtd->dai_link->be_id] > 0) { - ret = msm_transcode_map_ion_fd(trans, - pdata->ion_fd[rtd->dai_link->be_id]); - if (ret < 0) - goto exit; - } } pr_debug("%s: num stream%d, stream name %s\n", __func__, @@ -320,7 +237,8 @@ static int msm_transcode_loopback_open(struct snd_compr_stream *cstream) } runtime->private_data = trans; - + if (trans->num_streams == 1) + msm_adsp_init_mixer_ctl_pp_event_queue(rtd); exit: mutex_unlock(&trans->lock); return ret; @@ -356,11 +274,7 @@ static int msm_transcode_loopback_free(struct snd_compr_stream *cstream) struct snd_compr_runtime *runtime = cstream->runtime; struct msm_transcode_loopback *trans = runtime->private_data; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(cstream); - struct trans_loopback_pdata *pdata = snd_soc_platform_get_drvdata( - rtd->platform); int ret = 0; - ion_phys_addr_t paddr; - size_t pa_len = 0; mutex_lock(&trans->lock); @@ -369,24 +283,14 @@ static int msm_transcode_loopback_free(struct snd_compr_stream *cstream) trans->num_streams--; stop_transcoding(trans); - if (cstream->direction == SND_COMPRESS_PLAYBACK) { + if (cstream->direction == SND_COMPRESS_PLAYBACK) memset(&trans->sink, 0, sizeof(struct loopback_stream)); - msm_adsp_clean_mixer_ctl_pp_event_queue(rtd); - if (trans->shm_ion_fd > 0) { - msm_audio_ion_phys_free(trans->shm_ion_client, - trans->shm_ion_handle, - &paddr, &pa_len, ADSP_TO_HLOS); - trans->shm_ion_fd = 0; - } - if (pdata->ion_fd[rtd->dai_link->be_id] > 0) { - msm_transcode_unmap_ion_fd(trans); - pdata->ion_fd[rtd->dai_link->be_id] = 0; - } - } else if (cstream->direction == SND_COMPRESS_CAPTURE) { + else if (cstream->direction == SND_COMPRESS_CAPTURE) memset(&trans->source, 0, sizeof(struct loopback_stream)); - } trans->session_state = LOOPBACK_SESSION_CLOSE; + if (trans->num_streams == 1) + msm_adsp_clean_mixer_ctl_pp_event_queue(rtd); mutex_unlock(&trans->lock); return ret; } @@ -433,8 +337,6 @@ static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream, struct msm_transcode_loopback *trans = runtime->private_data; struct snd_soc_pcm_runtime *soc_pcm_rx; struct snd_soc_pcm_runtime *soc_pcm_tx; - struct snd_soc_pcm_runtime *rtd; - struct trans_loopback_pdata *pdata; uint32_t bit_width = 16; int ret = 0; @@ -445,9 +347,6 @@ static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream, mutex_lock(&trans->lock); - rtd = snd_pcm_substream_chip(cstream); - pdata = snd_soc_platform_get_drvdata(rtd->platform); - if (cstream->direction == SND_COMPRESS_PLAYBACK) { if (codec_param->codec.id == SND_AUDIOCODEC_PCM) { trans->sink.codec_format = @@ -529,7 +428,7 @@ static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream, pr_debug("%s: ASM client allocated, callback %pK\n", __func__, loopback_event_handler); trans->session_id = trans->audio_client->session; - trans->audio_client->perf_mode = pdata->perf_mode; + trans->audio_client->perf_mode = false; ret = q6asm_open_transcode_loopback(trans->audio_client, bit_width, trans->source.codec_format, @@ -548,7 +447,7 @@ static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream, if (trans->source.codec_format != FORMAT_LINEAR_PCM) msm_pcm_routing_reg_phy_compr_stream( soc_pcm_tx->dai_link->be_id, - false, + trans->audio_client->perf_mode, trans->session_id, SNDRV_PCM_STREAM_CAPTURE, COMPRESSED_PASSTHROUGH_GEN); @@ -561,7 +460,7 @@ static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream, /* Opening Rx ADM in LOW_LATENCY mode by default */ msm_pcm_routing_reg_phy_stream( soc_pcm_rx->dai_link->be_id, - trans->audio_client->perf_mode, + true, trans->session_id, SNDRV_PCM_STREAM_PLAYBACK); pr_debug("%s: Successfully opened ADM sessions\n", __func__); @@ -594,46 +493,6 @@ static int msm_transcode_loopback_get_caps(struct snd_compr_stream *cstream, return 0; } -static int msm_transcode_loopback_set_metadata(struct snd_compr_stream *cstream, - struct snd_compr_metadata *metadata) -{ - struct snd_soc_pcm_runtime *rtd; - struct trans_loopback_pdata *pdata; - - if (!metadata || !cstream) { - pr_err("%s: Invalid arguments\n", __func__); - return -EINVAL; - } - - rtd = snd_pcm_substream_chip(cstream); - pdata = snd_soc_platform_get_drvdata(rtd->platform); - - switch (metadata->key) { - case SNDRV_COMPRESS_LATENCY_MODE: - { - switch (metadata->value[0]) { - case SNDRV_COMPRESS_LEGACY_LATENCY_MODE: - pdata->perf_mode = LEGACY_PCM_MODE; - break; - case SNDRV_COMPRESS_LOW_LATENCY_MODE: - pdata->perf_mode = LOW_LATENCY_PCM_MODE; - break; - default: - pr_debug("%s: Unsupported latency mode %d, default to Legacy\n", - __func__, metadata->value[0]); - pdata->perf_mode = LEGACY_PCM_MODE; - break; - } - } - break; - default: - pr_debug("%s: Unsupported metadata %d\n", - __func__, metadata->key); - break; - } - return 0; -} - static int msm_transcode_stream_cmd_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -698,7 +557,7 @@ done: return ret; } -static int msm_transcode_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol, +static int msm_transcode_ion_fd_map_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); @@ -707,6 +566,7 @@ static int msm_transcode_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol, snd_soc_component_get_drvdata(comp); struct snd_compr_stream *cstream = NULL; struct msm_transcode_loopback *prtd; + int fd; int ret = 0; if (fe_id >= MSM_FRONTEND_DAI_MAX) { @@ -736,36 +596,10 @@ static int msm_transcode_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol, goto done; } - memcpy(&prtd->shm_ion_fd, ucontrol->value.bytes.data, - sizeof(prtd->shm_ion_fd)); - ret = q6asm_audio_map_shm_fd(prtd->audio_client, - &prtd->shm_ion_client, - &prtd->shm_ion_handle, prtd->shm_ion_fd); + memcpy(&fd, ucontrol->value.bytes.data, sizeof(fd)); + ret = q6asm_send_ion_fd(prtd->audio_client, fd); if (ret < 0) - pr_err("%s: failed to map shm mem\n", __func__); -done: - return ret; -} - - -static int msm_transcode_lib_ion_fd_map_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); - unsigned long fe_id = kcontrol->private_value; - struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *) - snd_soc_component_get_drvdata(comp); - int ret = 0; - - if (fe_id >= MSM_FRONTEND_DAI_MAX) { - pr_err("%s Received out of bounds invalid fe_id %lu\n", - __func__, fe_id); - ret = -EINVAL; - goto done; - } - - memcpy(&pdata->ion_fd[fe_id], ucontrol->value.bytes.data, - sizeof(pdata->ion_fd[fe_id])); + pr_err("%s: failed to register ion fd\n", __func__); done: return ret; } @@ -829,141 +663,6 @@ done: return ret; } -static int msm_transcode_playback_app_type_cfg_put( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u64 fe_id = kcontrol->private_value; - int session_type = SESSION_TYPE_RX; - int be_id = ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_BE_ID]; - struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000}; - int ret = 0; - - cfg_data.app_type = ucontrol->value.integer.value[ - APP_TYPE_CONFIG_IDX_APP_TYPE]; - cfg_data.acdb_dev_id = ucontrol->value.integer.value[ - APP_TYPE_CONFIG_IDX_ACDB_ID]; - if (ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_SAMPLE_RATE] != 0) - cfg_data.sample_rate = ucontrol->value.integer.value[ - APP_TYPE_CONFIG_IDX_SAMPLE_RATE]; - pr_debug("%s: fe_id %llu session_type %d be_id %d app_type %d acdb_dev_id %d sample_rate- %d\n", - __func__, fe_id, session_type, be_id, - cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate); - ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type, - be_id, &cfg_data); - if (ret < 0) - pr_err("%s: msm_transcode_playback_stream_app_type_cfg set failed returned %d\n", - __func__, ret); - - return ret; -} - -static int msm_transcode_playback_app_type_cfg_get( - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u64 fe_id = kcontrol->private_value; - int session_type = SESSION_TYPE_RX; - int be_id = 0; - struct msm_pcm_stream_app_type_cfg cfg_data = {0}; - int ret = 0; - - ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type, - &be_id, &cfg_data); - if (ret < 0) { - pr_err("%s: msm_transcode_playback_stream_app_type_cfg get failed returned %d\n", - __func__, ret); - goto done; - } - - ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_APP_TYPE] = - cfg_data.app_type; - ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_ACDB_ID] = - cfg_data.acdb_dev_id; - ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_SAMPLE_RATE] = - cfg_data.sample_rate; - ucontrol->value.integer.value[APP_TYPE_CONFIG_IDX_BE_ID] = be_id; - pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n", - __func__, fe_id, session_type, be_id, - cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate); -done: - return ret; -} - -static int msm_transcode_set_volume(struct snd_compr_stream *cstream, - uint32_t master_gain) -{ - int rc = 0; - struct msm_transcode_loopback *prtd; - struct snd_soc_pcm_runtime *rtd; - - pr_debug("%s: master_gain %d\n", __func__, master_gain); - if (!cstream || !cstream->runtime) { - pr_err("%s: session not active\n", __func__); - return -EPERM; - } - rtd = cstream->private_data; - prtd = cstream->runtime->private_data; - - if (!rtd || !rtd->platform || !prtd || !prtd->audio_client) { - pr_err("%s: invalid rtd, prtd or audio client", __func__); - return -EINVAL; - } - - rc = q6asm_set_volume(prtd->audio_client, master_gain); - if (rc < 0) - pr_err("%s: Send vol gain command failed rc=%d\n", - __func__, rc); - - return rc; -} - -static int msm_transcode_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); - unsigned long fe_id = kcontrol->private_value; - struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *) - snd_soc_component_get_drvdata(comp); - struct snd_compr_stream *cstream = NULL; - uint32_t ret = 0; - - if (fe_id >= MSM_FRONTEND_DAI_MAX) { - pr_err("%s Received out of bounds fe_id %lu\n", - __func__, fe_id); - return -EINVAL; - } - - cstream = pdata->cstream[fe_id]; - pdata->master_gain = ucontrol->value.integer.value[0]; - - pr_debug("%s: fe_id %lu master_gain %d\n", - __func__, fe_id, pdata->master_gain); - if (cstream) - ret = msm_transcode_set_volume(cstream, pdata->master_gain); - return ret; -} - -static int msm_transcode_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); - unsigned long fe_id = kcontrol->private_value; - - struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *) - snd_soc_component_get_drvdata(comp); - - if (fe_id >= MSM_FRONTEND_DAI_MAX) { - pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id); - return -EINVAL; - } - - pr_debug("%s: fe_id %lu\n", __func__, fe_id); - ucontrol->value.integer.value[0] = pdata->master_gain; - - return 0; -} - static int msm_transcode_stream_cmd_control( struct snd_soc_pcm_runtime *rtd) { @@ -1074,8 +773,7 @@ done: return ret; } -static int msm_transcode_add_shm_ion_fd_cmd_control( - struct snd_soc_pcm_runtime *rtd) +static int msm_transcode_add_ion_fd_cmd_control(struct snd_soc_pcm_runtime *rtd) { const char *mixer_ctl_name = "Playback ION FD"; const char *deviceNo = "NN"; @@ -1087,53 +785,7 @@ static int msm_transcode_add_shm_ion_fd_cmd_control( .name = "?", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = msm_adsp_stream_cmd_info, - .put = msm_transcode_shm_ion_fd_map_put, - .private_value = 0, - } - }; - - if (!rtd) { - pr_err("%s NULL rtd\n", __func__); - ret = -EINVAL; - goto done; - } - - ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; - mixer_str = kzalloc(ctl_len, GFP_KERNEL); - if (!mixer_str) { - ret = -ENOMEM; - goto done; - } - - snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); - fe_ion_fd_config_control[0].name = mixer_str; - fe_ion_fd_config_control[0].private_value = rtd->dai_link->be_id; - pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); - ret = snd_soc_add_platform_controls(rtd->platform, - fe_ion_fd_config_control, - ARRAY_SIZE(fe_ion_fd_config_control)); - if (ret < 0) - pr_err("%s: failed to add ctl %s\n", __func__, mixer_str); - - kfree(mixer_str); -done: - return ret; -} - -static int msm_transcode_add_lib_ion_fd_cmd_control( - struct snd_soc_pcm_runtime *rtd) -{ - const char *mixer_ctl_name = "Playback ION LIB FD"; - const char *deviceNo = "NN"; - char *mixer_str = NULL; - int ctl_len = 0, ret = 0; - struct snd_kcontrol_new fe_ion_fd_config_control[1] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "?", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = msm_adsp_stream_cmd_info, - .put = msm_transcode_lib_ion_fd_map_put, + .put = msm_transcode_ion_fd_map_put, .private_value = 0, } }; @@ -1212,99 +864,6 @@ done: return ret; } -static int msm_transcode_app_type_cfg_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 5; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 0xFFFFFFFF; - return 0; -} - -static int msm_transcode_add_app_type_cfg_control( - struct snd_soc_pcm_runtime *rtd) -{ - char mixer_str[32]; - int rc = 0; - struct snd_kcontrol_new fe_app_type_cfg_control[1] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = msm_transcode_app_type_cfg_info, - .put = msm_transcode_playback_app_type_cfg_put, - .get = msm_transcode_playback_app_type_cfg_get, - .private_value = 0, - } - }; - - if (!rtd) { - pr_err("%s NULL rtd\n", __func__); - - return -EINVAL; - } - - if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) { - - snprintf(mixer_str, sizeof(mixer_str), - "Audio Stream %d App Type Cfg", - rtd->pcm->device); - - fe_app_type_cfg_control[0].name = mixer_str; - fe_app_type_cfg_control[0].private_value = rtd->dai_link->be_id; - - fe_app_type_cfg_control[0].put = - msm_transcode_playback_app_type_cfg_put; - fe_app_type_cfg_control[0].get = - msm_transcode_playback_app_type_cfg_get; - - pr_debug("Registering new mixer ctl %s", mixer_str); - snd_soc_add_platform_controls(rtd->platform, - fe_app_type_cfg_control, - ARRAY_SIZE(fe_app_type_cfg_control)); - } - - return rc; -} -static int msm_transcode_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = TRANSCODE_LR_VOL_MAX_STEPS; - return 0; -} - -static int msm_transcode_add_volume_control(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_kcontrol_new fe_volume_control[1] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Transcode Loopback Rx Volume", - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = msm_transcode_volume_info, - .get = msm_transcode_volume_get, - .put = msm_transcode_volume_put, - .private_value = 0, - } - }; - - if (!rtd) { - pr_err("%s NULL rtd\n", __func__); - return -EINVAL; - } - if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) { - fe_volume_control[0].private_value = rtd->dai_link->be_id; - pr_debug("Registering new mixer ctl %s", - fe_volume_control[0].name); - snd_soc_add_platform_controls(rtd->platform, fe_volume_control, - ARRAY_SIZE(fe_volume_control)); - } - return 0; -} - static int msm_transcode_loopback_new(struct snd_soc_pcm_runtime *rtd) { int rc; @@ -1318,14 +877,9 @@ static int msm_transcode_loopback_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: ADSP Stream callback Control open failed\n", __func__); - rc = msm_transcode_add_shm_ion_fd_cmd_control(rtd); + rc = msm_transcode_add_ion_fd_cmd_control(rtd); if (rc) - pr_err("%s: Could not add transcode shm ion fd Control\n", - __func__); - - rc = msm_transcode_add_lib_ion_fd_cmd_control(rtd); - if (rc) - pr_err("%s: Could not add transcode lib ion fd Control\n", + pr_err("%s: Could not add transcode ion fd Control\n", __func__); rc = msm_transcode_add_event_ack_cmd_control(rtd); @@ -1333,16 +887,6 @@ static int msm_transcode_loopback_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add transcode event ack Control\n", __func__); - rc = msm_transcode_add_app_type_cfg_control(rtd); - if (rc) - pr_err("%s: Could not add Compr App Type Cfg Control\n", - __func__); - - rc = msm_transcode_add_volume_control(rtd); - if (rc) - pr_err("%s: Could not add transcode volume Control\n", - __func__); - return 0; } @@ -1352,7 +896,6 @@ static struct snd_compr_ops msm_transcode_loopback_ops = { .trigger = msm_transcode_loopback_trigger, .set_params = msm_transcode_loopback_set_params, .get_caps = msm_transcode_loopback_get_caps, - .set_metadata = msm_transcode_loopback_set_metadata, }; @@ -1367,7 +910,6 @@ static int msm_transcode_loopback_probe(struct snd_soc_platform *platform) if (!pdata) return -ENOMEM; - pdata->perf_mode = LOW_LATENCY_PCM_MODE; snd_soc_platform_set_drvdata(platform, pdata); return 0; } diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c index 018681309f2ec2e43599a37ca28766504be9d0e5..5f90fc9c1abfac13df947a69052fffae2c56aa6b 100644 --- a/sound/soc/msm/qdsp6v2/q6adm.c +++ b/sound/soc/msm/qdsp6v2/q6adm.c @@ -9,6 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -48,6 +53,16 @@ #define DS2_ADM_COPP_TOPOLOGY_ID 0xFFFFFFFF #endif +#ifdef CONFIG_FORCE_24BIT_COPP +#define APPTYPE_GENERAL_PLAYBACK 0x00011130 +#endif + +/* ENUM for adm_status */ +enum adm_cal_status { + ADM_STATUS_CALIBRATION_REQUIRED = 0, + ADM_STATUS_MAX, +}; + struct adm_copp { atomic_t id[AFE_MAX_PORTS][MAX_COPPS_PER_PORT]; @@ -775,9 +790,9 @@ fail_cmd: return ret; } -int adm_set_pspd_matrix_params(int port_id, int copp_idx, - unsigned int session_id, char *params, - uint32_t params_length) +int adm_set_stereo_to_custom_stereo(int port_id, int copp_idx, + unsigned int session_id, char *params, + uint32_t params_length) { struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL; int sz, rc = 0, port_idx; @@ -1011,6 +1026,81 @@ send_param_return: return rc; } +int adm_ahc_send_params(int port_id, int copp_idx, char *params, + uint32_t params_length) +{ + struct adm_cmd_set_pp_params_v5 *adm_params = NULL; + int sz, rc = 0; + int port_idx; + + pr_debug("%s:\n", __func__); + port_id = afe_convert_virtual_to_portid(port_id); + port_idx = adm_validate_and_get_port_index(port_id); + if (port_idx < 0) { + pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id); + return -EINVAL; + } + + sz = sizeof(struct adm_cmd_set_pp_params_v5) + params_length; + adm_params = kzalloc(sz, GFP_KERNEL); + if (!adm_params) { + pr_err("%s, adm params memory alloc failed", __func__); + return -ENOMEM; + } + + memcpy(((u8 *)adm_params + sizeof(struct adm_cmd_set_pp_params_v5)), + params, params_length); + adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + adm_params->hdr.pkt_size = sz; + adm_params->hdr.src_svc = APR_SVC_ADM; + adm_params->hdr.src_domain = APR_DOMAIN_APPS; + adm_params->hdr.src_port = port_id; + adm_params->hdr.dest_svc = APR_SVC_ADM; + adm_params->hdr.dest_domain = APR_DOMAIN_ADSP; + adm_params->hdr.dest_port = + atomic_read(&this_adm.copp.id[port_idx][copp_idx]); + adm_params->hdr.token = port_idx << 16 | copp_idx; + adm_params->hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5; + adm_params->payload_addr_lsw = 0; + adm_params->payload_addr_msw = 0; + adm_params->mem_map_handle = 0; + adm_params->payload_size = params_length; + + atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1); + rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params); + if (rc < 0) { + pr_err("%s: Set params failed port = 0x%x rc %d\n", + __func__, port_id, rc); + rc = -EINVAL; + goto ahc_send_param_return; + } + /* Wait for the callback */ + rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx], + atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0, + msecs_to_jiffies(TIMEOUT_MS)); + if (!rc) { + pr_err("%s: Set params timed out port = 0x%x\n", + __func__, port_id); + rc = -EINVAL; + goto ahc_send_param_return; + } else if (atomic_read(&this_adm.copp.stat + [port_idx][copp_idx]) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&this_adm.copp.stat + [port_idx][copp_idx]))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&this_adm.copp.stat + [port_idx][copp_idx])); + goto ahc_send_param_return; + } + rc = 0; +ahc_send_param_return: + kfree(adm_params); + return rc; +} + int adm_get_params_v2(int port_id, int copp_idx, uint32_t module_id, uint32_t param_id, uint32_t params_length, char *params, uint32_t client_id) @@ -1407,7 +1497,7 @@ static int32_t adm_callback(struct apr_client_data *data, void *priv) case ADM_CMD_DEVICE_OPEN_V5: case ADM_CMD_DEVICE_CLOSE_V5: case ADM_CMD_DEVICE_OPEN_V6: - case ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1: + case ADM_CMD_MATRIX_MUTE_V5: pr_debug("%s: Basic callback received, wake up.\n", __func__); atomic_set(&this_adm.copp.stat[port_idx] @@ -2147,6 +2237,107 @@ static void send_adm_cal(int port_id, int copp_idx, int path, int perf_mode, return; } +int adm_matrix_mute(int port_id, int session_id, uint32_t ramp_duration, + uint32_t mute_flag_ch1, uint32_t mute_flag_ch2) +{ + struct adm_cmd_matrix_mute_v5 *apr = NULL; + + int cmd_size = 0; + int ret = 0; + void *matrix_mute = NULL; + int port_idx, copp_idx = 0; + + port_id = q6audio_convert_virtual_to_portid(port_id); + port_idx = adm_validate_and_get_port_index(port_id); + if (port_idx < 0) { + pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id); + return -EINVAL; + } + + if (this_adm.apr == NULL) { + this_adm.apr = apr_register("ADSP", "ADM", adm_callback, + 0xFFFFFFFF, &this_adm); + if (this_adm.apr == NULL) { + pr_err("%s: Unable to register ADM\n", __func__); + ret = -ENODEV; + return ret; + } + rtac_set_adm_handle(this_adm.apr); + } + + cmd_size = sizeof(struct adm_cmd_matrix_mute_v5); + matrix_mute = kzalloc(cmd_size, GFP_KERNEL); + if (matrix_mute == NULL) { + pr_err("%s: Mem alloc failed\n", __func__); + ret = -EINVAL; + return ret; + } + apr = (struct adm_cmd_matrix_mute_v5 *)matrix_mute; + + pr_debug("%s: Port ID 0x%x, index %d\n", __func__, port_id, port_idx); + + /* APR header field */ + apr->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + apr->hdr.pkt_size = cmd_size; + apr->hdr.src_svc = APR_SVC_ADM; + apr->hdr.src_domain = APR_DOMAIN_APPS; + apr->hdr.src_port = 0; + apr->hdr.dest_svc = APR_SVC_ADM; + apr->hdr.dest_domain = APR_DOMAIN_ADSP; + apr->hdr.dest_port = atomic_read(&this_adm.copp.id[port_idx][copp_idx]); + apr->hdr.token = port_idx << 16 | copp_idx; + apr->hdr.opcode = ADM_CMD_MATRIX_MUTE_V5; + /* APR message payload */ + apr->matrix_id = ADM_MATRIX_ID_AUDIO_RX; + apr->session_id = session_id; + apr->copp_id = ADM_CMD_MATRIX_MUTE_COPP_ID_ALL_CONNECTED_COPPS; + apr->mute_flag_ch_1 = mute_flag_ch1; + apr->mute_flag_ch_2 = mute_flag_ch2; + apr->mute_flag_ch_3 = 0; + apr->mute_flag_ch_4 = 0; + apr->mute_flag_ch_5 = 0; + apr->mute_flag_ch_6 = 0; + apr->mute_flag_ch_7 = 0; + apr->mute_flag_ch_8 = 0; + apr->ramp_duration = ramp_duration; + apr->reserved_for_align = 0; + + atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1); + ret = apr_send_pkt(this_adm.apr, (uint32_t *)matrix_mute); + if (ret < 0) { + pr_err("%s: Set params failed port = %#x\n", + __func__, port_id); + ret = -EINVAL; + goto adm_matrix_mute_return; + } + /* Wait for the callback */ + ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx], + atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0, + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: Set params timed out port = %#x\n", + __func__, port_id); + ret = -EINVAL; + goto adm_matrix_mute_return; + } else if (atomic_read(&this_adm.copp.stat + [port_idx][copp_idx]) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&this_adm.copp.stat + [port_idx][copp_idx]))); + ret = adsp_err_get_lnx_err_code( + atomic_read(&this_adm.copp.stat + [port_idx][copp_idx])); + goto adm_matrix_mute_return; + } + ret = 0; + +adm_matrix_mute_return: + kfree(matrix_mute); + return ret; +} + int adm_connect_afe_port(int mode, int session_id, int port_id) { struct adm_cmd_connect_afe_port_v5 cmd; @@ -2364,14 +2555,27 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, struct adm_cmd_device_open_v5 open; struct adm_cmd_device_open_v6 open_v6; int ret = 0; - int port_idx, flags; - int copp_idx = -1; + int port_idx, copp_idx, flags; int tmp_port = q6audio_get_port_id(port_id); pr_debug("%s:port %#x path:%d rate:%d mode:%d perf_mode:%d,topo_id %d\n", __func__, port_id, path, rate, channel_mode, perf_mode, topology); +#ifdef CONFIG_FORCE_24BIT_COPP + if ((topology == ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_STEREO_AUDIO_COPP_SOMC_HP) && + (app_type == APPTYPE_GENERAL_PLAYBACK)) { + bit_width = 24; + pr_debug("%s: Force open adm in 24-bit for SOMC HP topology 0x%x\n", + __func__, topology); + } else if (((topology == ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_RX_MCH_IIR_COPP_MBDRC_V3) || + (topology == ADM_CMD_COPP_OPENOPOLOGY_ID_SPEAKER_RX_MCH_FIR_IIR_COPP_MBDRC_V3)) && + (app_type == APPTYPE_GENERAL_PLAYBACK)) { + bit_width = 24; + pr_debug("%s: Force open adm in 24-bit for SOMC Speaker topology 0x%x\n", + __func__, topology); + } +#endif port_id = q6audio_convert_virtual_to_portid(port_id); port_idx = adm_validate_and_get_port_index(port_id); if (port_idx < 0) { @@ -2416,20 +2620,13 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, if ((topology == VPM_TX_SM_ECNS_COPP_TOPOLOGY) || (topology == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) || - (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY)) + (topology == VPM_TX_DM_RFECNS_COPP_TOPOLOGY) || + (topology == VOICE_TOPOLOGY_LVVEFQ_TX_SM) || + (topology == VOICE_TOPOLOGY_LVVEFQ_TX_DM)) rate = 16000; - /* - * Routing driver reuses the same adm for streams with the same - * app_type, sample_rate etc. - * This isn't allowed for ULL streams as per the DSP interface - */ - if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) - copp_idx = adm_get_idx_if_copp_exists(port_idx, topology, - perf_mode, - rate, bit_width, - app_type); - + copp_idx = adm_get_idx_if_copp_exists(port_idx, topology, perf_mode, + rate, bit_width, app_type); if (copp_idx < 0) { copp_idx = adm_get_next_available_copp(port_idx); if (copp_idx >= MAX_COPPS_PER_PORT) { @@ -2700,97 +2897,6 @@ fail_cmd: return; } - -static int adm_set_mtmx_params_v1(int port_idx, int copp_idx, - int params_length, void *params) -{ - struct adm_cmd_set_mtmx_params_v1 *adm_params = NULL; - int rc = 0; - int sz; - - sz = sizeof(*adm_params) + params_length; - adm_params = kzalloc(sz, GFP_KERNEL); - if (!adm_params) - return -ENOMEM; - - memcpy(((u8 *)adm_params + sizeof(*adm_params)), - params, params_length); - adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, - APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); - adm_params->hdr.pkt_size = sz; - adm_params->hdr.src_svc = APR_SVC_ADM; - adm_params->hdr.src_domain = APR_DOMAIN_APPS; - adm_params->hdr.src_port = 0; - adm_params->hdr.dest_svc = APR_SVC_ADM; - adm_params->hdr.dest_domain = APR_DOMAIN_ADSP; - adm_params->hdr.dest_port = - atomic_read(&this_adm.copp.id[port_idx][copp_idx]); - adm_params->hdr.token = port_idx << 16 | copp_idx; - adm_params->hdr.opcode = ADM_CMD_SET_MTMX_STRTR_DEV_PARAMS_V1; - adm_params->payload_addr_lsw = 0; - adm_params->payload_addr_msw = 0; - adm_params->mem_map_handle = 0; - adm_params->payload_size = params_length; - adm_params->copp_id = atomic_read(&this_adm.copp. - id[port_idx][copp_idx]); - - atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1); - rc = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params); - if (rc < 0) { - pr_err("%s: Set params failed port_idx = 0x%x rc %d\n", - __func__, port_idx, rc); - rc = -EINVAL; - goto send_param_return; - } - /* Wait for the callback */ - rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx], - atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0, - msecs_to_jiffies(TIMEOUT_MS)); - if (!rc) { - pr_err("%s: Set params timed out port_idx = 0x%x\n", - __func__, port_idx); - rc = -EINVAL; - goto send_param_return; - } else if (atomic_read(&this_adm.copp.stat - [port_idx][copp_idx]) > 0) { - pr_err("%s: DSP returned error[%s]\n", - __func__, adsp_err_get_err_str( - atomic_read(&this_adm.copp.stat - [port_idx][copp_idx]))); - rc = adsp_err_get_lnx_err_code( - atomic_read(&this_adm.copp.stat - [port_idx][copp_idx])); - goto send_param_return; - } - rc = 0; -send_param_return: - kfree(adm_params); - return rc; -} - -static void adm_enable_mtmx_limiter(int port_idx, int copp_idx) -{ - int rc; - struct enable_param_v6 adm_param = { {0} }; - - adm_param.param.module_id = ADM_MTMX_MODULE_STREAM_LIMITER; - adm_param.param.param_id = AUDPROC_PARAM_ID_ENABLE; - adm_param.param.param_size = sizeof(adm_param.enable); - adm_param.enable = 1; - - rc = adm_set_mtmx_params_v1(port_idx, copp_idx, - sizeof(adm_param), &adm_param); - if (rc < 0) { - pr_err("%s: adm_set_mtmx_params_v1 failed port_idx = 0x%x rc %d\n", - __func__, port_idx, rc); - goto done; - } - set_bit(ADM_STATUS_LIMITER, - (void *)&this_adm.copp.adm_status[port_idx][copp_idx]); -done: - return; -} - static void route_set_opcode_matrix_id( struct adm_cmd_matrix_map_routings_v5 **route_addr, int path, uint32_t passthr_mode) @@ -2887,11 +2993,6 @@ int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode, copp_idx = payload_map.copp_idx[i]; copps_list[i] = atomic_read(&this_adm.copp.id[port_idx] [copp_idx]); - if (test_bit(ADM_STATUS_LIMITER, - (void *)&payload_map.route_status) && - ((path == ADM_PATH_PLAYBACK) || - (path == ADM_PATH_COMPRESSED_RX))) - adm_enable_mtmx_limiter(port_idx, copp_idx); } atomic_set(&this_adm.matrix_map_stat, -1); @@ -3092,8 +3193,6 @@ int adm_close(int port_id, int perf_mode, int copp_idx) clear_bit(ADM_STATUS_CALIBRATION_REQUIRED, (void *)&this_adm.copp.adm_status[port_idx][copp_idx]); - clear_bit(ADM_STATUS_LIMITER, - (void *)&this_adm.copp.adm_status[port_idx][copp_idx]); ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close); if (ret < 0) { @@ -4910,7 +5009,8 @@ static int __init adm_init(void) &this_adm.copp.adm_delay_wait[i][j]); atomic_set(&this_adm.copp.topology[i][j], 0); this_adm.copp.adm_delay[i][j] = 0; - this_adm.copp.adm_status[i][j] = 0; + this_adm.copp.adm_status[i][j] = + ADM_STATUS_CALIBRATION_REQUIRED; } } diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index c3d86e6cced2889e056d37013d13880ccfff36d7..28e518aa6544dfdbe645c84e803188a59fe92e67 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -12,6 +12,11 @@ * GNU General Public License for more details. * */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #include #include #include @@ -36,16 +41,18 @@ #include #include -#include #include #include #include #include +#include "sound/sony-hweffect.h" +#include "sound/sony-hweffect-params.h" + #define TRUE 0x01 #define FALSE 0x00 -#define SESSION_MAX 9 -#define ASM_MAX_CHANNELS 8 +#define SESSION_MAX 8 + enum { ASM_TOPOLOGY_CAL = 0, ASM_CUSTOM_TOP_CAL, @@ -84,6 +91,17 @@ enum { #define ASM_SET_BIT(n, x) (n |= 1 << x) #define ASM_TEST_BIT(n, x) ((n >> x) & 1) +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif +#define ONCE_PARAM_SIZE 460 + +struct param_divide { + uint8_t divide_num; + uint8_t no; + uint16_t offset; +}; + /* TODO, combine them together */ static DEFINE_MUTEX(session_lock); struct asm_mmap { @@ -424,22 +442,14 @@ static void config_debug_fs_run(void) } } -static void config_debug_fs_write(struct audio_buffer *ab, int offset) +static void config_debug_fs_write(struct audio_buffer *ab) { if (out_enable_flag) { char zero_pattern[2] = {0x00, 0x00}; - char *data; - - if ((offset < 0) || (offset > ab->size)) { - pr_err("Invalid offset %d", offset); - return; - } - - data = (char *)ab->data + offset; /* If First two byte is non zero and last two byte is zero then it is warm output pattern */ - if ((strncmp(data, zero_pattern, 2)) && - (!strncmp((data + 2), zero_pattern, 2))) { + if ((strncmp(((char *)ab->data), zero_pattern, 2)) && + (!strncmp(((char *)ab->data + 2), zero_pattern, 2))) { do_gettimeofday(&out_warm_tv); pr_debug("%s: WARM:apr_send_pkt at %ld sec %ld microsec\n", __func__, @@ -449,8 +459,8 @@ static void config_debug_fs_write(struct audio_buffer *ab, int offset) } /* If First two byte is zero and last two byte is non zero then it is cont ouput pattern */ - else if ((!strncmp(data, zero_pattern, 2)) - && (strncmp((data + 2), zero_pattern, 2))) { + else if ((!strncmp(((char *)ab->data), zero_pattern, 2)) + && (strncmp(((char *)ab->data + 2), zero_pattern, 2))) { do_gettimeofday(&out_cont_tv); pr_debug("%s: CONT:apr_send_pkt at %ld sec %ld microsec\n", __func__, @@ -497,7 +507,7 @@ outbuf_fail: return; } #else -static void config_debug_fs_write(struct audio_buffer *ab, int offset) +static void config_debug_fs_write(struct audio_buffer *ab) { return; } @@ -523,6 +533,136 @@ static void config_debug_fs_init(void) } #endif +/* SOMC effect control start */ + +int sony_hweffect_send_tuning_params(unsigned int effect_id, void *client) +{ + int rc = 0x00; + char *param, *tuning_param_s, *tuning_param_d; + uint32_t module_id, param_id; + uint32_t param_length; + struct asm_stream_param_data_v2 *param_data; + struct param_divide *divide; + uint32_t i, num, len, ret; + + pr_debug("%s: effect_id=%u\n", __func__, effect_id); + if (client == NULL) { + pr_err("%s: audio client is NULL\n", __func__); + return -EINVAL; + } + + param = kzalloc(MAX_INBAND_PARAM_SZ, GFP_KERNEL); + if (!param) { + pr_err("%s, param memory alloc failed\n", __func__); + return -ENOMEM; + } + + tuning_param_d = param + sizeof(struct asm_stream_param_data_v2); + + switch (effect_id) { + case SFORCE_PARAM: + tuning_param_s = sony_hweffect_params_getparam(SFORCE_PARAM); + if (tuning_param_s == NULL) { + pr_err("%s: sforce param is NULL\n", __func__); + rc = -EINVAL; + goto invalid_config; + } + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_SFORCE_TUNING; + param_length = sizeof(struct s_force_tuning_params); + pr_debug("%s: SFORCE_PARAM\n module_id=%u, param_id=%u, param_length=%u", + __func__, module_id, param_id, param_length); + break; + + case CLEARPHASE_HP_PARAM: + tuning_param_s = sony_hweffect_params_getparam( + CLEARPHASE_HP_PARAM); + if (tuning_param_s == NULL) { + pr_err("%s: clearphase_hp param is NULL\n", __func__); + rc = -EINVAL; + goto invalid_config; + } + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_CLEARPHASE_HP_TUNING; + param_length = sizeof(struct clearphase_hp_tuning_params); + pr_debug("%s: CLEARPHASE_HP_PARAM\n module_id=%u, param_id=%u, param_length=%u", + __func__, module_id, param_id, param_length); + break; + + case CLEARPHASE_SP_PARAM: + tuning_param_s = sony_hweffect_params_getparam( + CLEARPHASE_SP_PARAM); + if (tuning_param_s == NULL) { + pr_err("%s: clearphase_sp param is NULL\n", __func__); + rc = -EINVAL; + goto invalid_config; + } + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_CLEARPHASE_SP_TUNING; + param_length = sizeof(struct clearphase_sp_tuning_params); + pr_debug("%s: CLEARPHASE_SP_PARAM\n module_id=%u, param_id=%u, param_length=%u", + __func__, module_id, param_id, param_length); + break; + + case XLOUD_PARAM: + tuning_param_s = sony_hweffect_params_getparam(XLOUD_PARAM); + if (tuning_param_s == NULL) { + pr_err("%s: xloud param is NULL\n", __func__); + rc = -EINVAL; + goto invalid_config; + } + + module_id = ASM_MODULE_ID_SONYBUNDLE; + param_id = PARAM_ID_SB_XLOUD_TUNING; + param_length = sizeof(struct xloud_tuning_params); + pr_debug("%s: XLOUD_PARAM\n module_id=%u, param_id=%u, param_length=%u", + __func__, module_id, param_id, param_length); + break; + + default: + pr_err("%s: Invalid effect id(%u)\n", __func__, effect_id); + rc = -EINVAL; + goto invalid_config; + }; + + num = (param_length + ONCE_PARAM_SIZE - 1) / ONCE_PARAM_SIZE; + for (i = 0; i < num; i++) { + len = MIN(ONCE_PARAM_SIZE, param_length + - (i * ONCE_PARAM_SIZE)); + divide = (struct param_divide *)tuning_param_d; + divide->divide_num = (uint8_t)num; + divide->no = (uint8_t)i; + divide->offset = (uint16_t)(i * ONCE_PARAM_SIZE); + memcpy(tuning_param_d + sizeof(struct param_divide), + tuning_param_s + divide->offset, len); + len += sizeof(struct param_divide); + param_data = (struct asm_stream_param_data_v2 *)param; + param_data->module_id = module_id; + param_data->param_id = param_id; + param_data->param_size = (uint16_t)len; + param_data->reserved = 0; + len += sizeof(struct asm_stream_param_data_v2); + + ret = q6asm_send_audio_effects_params( + (struct audio_client *)client, + (char *)param, len); + if (ret < 0) { + pr_err("%s: set-param failed ret[%d]\n", __func__, ret); + rc = -EINVAL; + goto invalid_config; + } + } + +invalid_config: + kfree(param); + return rc; +} + +/* SOMC effect control end */ + int q6asm_mmap_apr_dereg(void) { int c; @@ -1338,7 +1478,7 @@ int q6asm_audio_client_buf_alloc(unsigned int dir, pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session, bufsz, bufcnt); - if (ac->session <= 0 || ac->session > ASM_ACTIVE_STREAMS_ALLOWED) { + if (ac->session <= 0 || ac->session > 8) { pr_err("%s: Session ID is invalid, session = %d\n", __func__, ac->session); goto fail; @@ -1429,7 +1569,7 @@ int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir, __func__, ac->session, bufsz, bufcnt); - if (ac->session <= 0 || ac->session > ASM_ACTIVE_STREAMS_ALLOWED) { + if (ac->session <= 0 || ac->session > 8) { pr_err("%s: Session ID is invalid, session = %d\n", __func__, ac->session); goto fail; @@ -1738,7 +1878,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) return -EINVAL; } - if (ac->session <= 0 || ac->session > ASM_ACTIVE_STREAMS_ALLOWED) { + if (ac->session <= 0 || ac->session > 8) { pr_err("%s: Session ID is invalid, session = %d\n", __func__, ac->session); return -EINVAL; @@ -3368,15 +3508,6 @@ int q6asm_set_shared_circ_buff(struct audio_client *ac, int bytes_to_alloc, rc; size_t len; - mutex_lock(&ac->cmd_lock); - - if (ac->port[dir].buf) { - pr_err("%s: Buffer already allocated\n", __func__); - rc = -EINVAL; - mutex_unlock(&ac->cmd_lock); - goto done; - } - buf_circ = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL); if (!buf_circ) { @@ -3384,6 +3515,10 @@ int q6asm_set_shared_circ_buff(struct audio_client *ac, goto done; } + mutex_lock(&ac->cmd_lock); + + ac->port[dir].buf = buf_circ; + bytes_to_alloc = bufsz * bufcnt; bytes_to_alloc = PAGE_ALIGN(bytes_to_alloc); @@ -3395,12 +3530,11 @@ int q6asm_set_shared_circ_buff(struct audio_client *ac, if (rc) { pr_err("%s: Audio ION alloc is failed, rc = %d\n", __func__, rc); - kfree(buf_circ); mutex_unlock(&ac->cmd_lock); + kfree(buf_circ); goto done; } - ac->port[dir].buf = buf_circ; buf_circ->used = dir ^ 1; buf_circ->size = bytes_to_alloc; buf_circ->actual_size = bytes_to_alloc; @@ -3565,6 +3699,12 @@ int q6asm_open_shared_io(struct audio_client *ac, goto done; } + if (ac->port[dir].buf) { + pr_err("%s: Buffer already allocated\n", __func__); + rc = -EINVAL; + goto done; + } + rc = q6asm_set_shared_circ_buff(ac, open, bufsz, bufcnt, dir); if (rc) @@ -7118,11 +7258,13 @@ fail_cmd: return rc; } -int q6asm_audio_map_shm_fd(struct audio_client *ac, struct ion_client **client, - struct ion_handle **handle, int fd) +int q6asm_send_ion_fd(struct audio_client *ac, int fd) { + struct ion_client *client; + struct ion_handle *handle; ion_phys_addr_t paddr; size_t pa_len = 0; + void *vaddr; int ret; int sz = 0; struct avs_rtic_shared_mem_addr shm; @@ -7138,11 +7280,19 @@ int q6asm_audio_map_shm_fd(struct audio_client *ac, struct ion_client **client, goto fail_cmd; } - ret = msm_audio_ion_phys_assign("audio_shm_mem_client", client, - handle, fd, - &paddr, &pa_len, HLOS_TO_ADSP); + ret = msm_audio_ion_import("audio_mem_client", + &client, + &handle, + fd, + NULL, + 0, + &paddr, + &pa_len, + &vaddr); if (ret) { - pr_err("%s: shm ION phys failed, rc = %d\n", __func__, ret); + pr_err("%s: audio ION import failed, rc = %d\n", + __func__, ret); + ret = -ENOMEM; goto fail_cmd; } /* get payload length */ @@ -7215,9 +7365,10 @@ int q6asm_send_rtic_event_ack(struct audio_client *ac, goto done; } - q6asm_stream_add_hdr_async(ac, &ack.hdr, + q6asm_add_hdr_async(ac, &ack.hdr, sizeof(struct avs_param_rtic_event_ack) + - params_length, TRUE, ac->stream_id); + params_length, TRUE); + atomic_set(&ac->cmd_state, -1); ack.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2; ack.encdec.param_id = AVS_PARAM_ID_RTIC_EVENT_ACK; ack.encdec.param_size = params_length; @@ -7227,11 +7378,31 @@ int q6asm_send_rtic_event_ack(struct audio_client *ac, memcpy(asm_params + sizeof(struct avs_param_rtic_event_ack), param, params_length); rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params); - if (rc < 0) + if (rc < 0) { pr_err("%s: apr pkt failed for rtic event ack\n", __func__); - else - rc = 0; + rc = -EINVAL; + goto fail_send_param; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 1 * HZ); + if (!rc) { + pr_err("%s: timeout for rtic event ack cmd\n", __func__); + rc = -ETIMEDOUT; + goto fail_send_param; + } + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s] for rtic event ack cmd\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_send_param; + } + rc = 0; + +fail_send_param: kfree(asm_params); done: return rc; @@ -7397,299 +7568,6 @@ int q6asm_set_softvolume_v2(struct audio_client *ac, return __q6asm_set_softvolume(ac, softvol_param, instance); } -int q6asm_set_vol_ctrl_gain_pair(struct audio_client *ac, - struct asm_stream_pan_ctrl_params *pan_param) -{ - int sz = 0; - int rc = 0; - int i = 0; - int32_t ch = 0; - struct apr_hdr hdr; - struct audproc_volume_ctrl_channel_type_gain_pair - gain_data[ASM_MAX_CHANNELS]; - struct asm_stream_cmd_set_pp_params_v2 payload_params; - struct asm_stream_param_data_v2 data; - uint16_t *asm_params = NULL; - - if (ac == NULL) { - pr_err("%s: ac is NULL\n", __func__); - rc = -EINVAL; - goto fail; - } - if (ac->apr == NULL) { - dev_err(ac->dev, "%s: ac apr handle NULL\n", __func__); - rc = -EINVAL; - goto fail; - } - - sz = sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2) + - sizeof(struct asm_stream_param_data_v2) + - sizeof(uint32_t) + - (sizeof(struct audproc_volume_ctrl_channel_type_gain_pair) * - ASM_MAX_CHANNELS); - asm_params = kzalloc(sz, GFP_KERNEL); - if (!asm_params) { - rc = -ENOMEM; - goto fail; - } - - q6asm_add_hdr_async(ac, &hdr, sz, TRUE); - atomic_set(&ac->cmd_state_pp, -1); - - hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2; - memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr)); - - payload_params.data_payload_addr_lsw = 0; - payload_params.data_payload_addr_msw = 0; - payload_params.mem_map_handle = 0; - payload_params.data_payload_size = - sizeof(struct asm_stream_param_data_v2) + - sizeof(uint32_t) + - (sizeof(struct audproc_volume_ctrl_channel_type_gain_pair) * - ASM_MAX_CHANNELS); - memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), - &payload_params, - sizeof(struct asm_stream_cmd_set_pp_params_v2)); - - data.module_id = AUDPROC_MODULE_ID_VOL_CTRL; - data.param_id = AUDPROC_PARAM_ID_MULTICHANNEL_GAIN; - data.param_size = sizeof(uint32_t) + - (sizeof(struct audproc_volume_ctrl_channel_type_gain_pair) * - ASM_MAX_CHANNELS); - data.reserved = 0; - memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2)), - &data, sizeof(struct asm_stream_param_data_v2)); - - ch = pan_param->num_output_channels; - memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2) + - sizeof(struct asm_stream_param_data_v2)), - &ch, - sizeof(uint32_t)); - - memset(gain_data, 0, - ASM_MAX_CHANNELS * - sizeof(struct audproc_volume_ctrl_channel_type_gain_pair)); - for (i = 0; i < pan_param->num_output_channels; i++) { - gain_data[i].channel_type = - pan_param->output_channel_map[i]; - gain_data[i].gain = pan_param->gain[i]; - } - memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2) + - sizeof(struct asm_stream_param_data_v2) + - sizeof(uint32_t)), - gain_data, - ASM_MAX_CHANNELS * - sizeof(struct audproc_volume_ctrl_channel_type_gain_pair)); - - rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params); - if (rc < 0) { - pr_err("%s: set-params send failed paramid[0x%x] rc %d\n", - __func__, data.param_id, rc); - goto done; - } - - rc = wait_event_timeout(ac->cmd_wait, - (atomic_read(&ac->cmd_state_pp) >= 0), 5 * HZ); - if (!rc) { - pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__, - data.param_id); - rc = -EINVAL; - goto done; - } - if (atomic_read(&ac->cmd_state_pp) > 0) { - pr_err("%s: DSP returned error[%d], set-params paramid[0x%x]\n", - __func__, atomic_read(&ac->cmd_state_pp), - data.param_id); - rc = -EINVAL; - goto done; - } - rc = 0; -done: - kfree(asm_params); -fail: - return rc; -} - -int q6asm_set_mfc_panning_params(struct audio_client *ac, - struct asm_stream_pan_ctrl_params *pan_param) -{ - int sz, rc, i; - struct audproc_mfc_output_media_fmt mfc_cfg; - struct apr_hdr hdr; - struct asm_stream_cmd_set_pp_params_v2 payload_params; - struct asm_stream_param_data_v2 data; - struct audproc_chmixer_param_coeff pan_cfg; - uint16_t variable_payload = 0; - char *asm_params = NULL; - uint16_t ii; - uint16_t *dst_gain_ptr = NULL; - - sz = rc = i = 0; - if (ac == NULL) { - pr_err("%s: ac handle NULL\n", __func__); - rc = -EINVAL; - goto fail_cmd1; - } - if (ac->apr == NULL) { - pr_err("%s: ac apr handle NULL\n", __func__); - rc = -EINVAL; - goto fail_cmd1; - } - - sz = sizeof(struct audproc_mfc_output_media_fmt); - q6asm_add_hdr_async(ac, &mfc_cfg.params.hdr, sz, TRUE); - atomic_set(&ac->cmd_state_pp, -1); - mfc_cfg.params.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2; - mfc_cfg.params.payload_addr_lsw = 0; - mfc_cfg.params.payload_addr_msw = 0; - mfc_cfg.params.mem_map_handle = 0; - mfc_cfg.params.payload_size = sizeof(mfc_cfg) - sizeof(mfc_cfg.params); - mfc_cfg.data.module_id = AUDPROC_MODULE_ID_MFC; - mfc_cfg.data.param_id = AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT; - mfc_cfg.data.param_size = mfc_cfg.params.payload_size - - sizeof(mfc_cfg.data); - mfc_cfg.data.reserved = 0; - mfc_cfg.sampling_rate = 0; - mfc_cfg.bits_per_sample = 0; - mfc_cfg.num_channels = pan_param->num_output_channels; - for (i = 0; i < mfc_cfg.num_channels; i++) - mfc_cfg.channel_type[i] = pan_param->output_channel_map[i]; - - rc = apr_send_pkt(ac->apr, (uint32_t *) &mfc_cfg); - if (rc < 0) { - pr_err("%s: set-params send failed paramid[0x%x] rc %d\n", - __func__, mfc_cfg.data.param_id, rc); - rc = -EINVAL; - goto fail_cmd1; - } - - rc = wait_event_timeout(ac->cmd_wait, - (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ); - if (!rc) { - pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__, - mfc_cfg.data.param_id); - rc = -ETIMEDOUT; - goto fail_cmd1; - } - if (atomic_read(&ac->cmd_state_pp) > 0) { - pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n", - __func__, adsp_err_get_err_str( - atomic_read(&ac->cmd_state_pp)), - mfc_cfg.data.param_id); - rc = adsp_err_get_lnx_err_code( - atomic_read(&ac->cmd_state_pp)); - goto fail_cmd1; - } - - variable_payload = pan_param->num_output_channels * sizeof(uint16_t)+ - pan_param->num_input_channels * sizeof(uint16_t) + - pan_param->num_output_channels * - pan_param->num_input_channels * sizeof(uint16_t); - i = (variable_payload % sizeof(uint32_t)); - variable_payload += (i == 0) ? 0 : sizeof(uint32_t) - i; - sz = sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2) + - sizeof(struct asm_stream_param_data_v2) + - sizeof(struct audproc_chmixer_param_coeff) + - variable_payload; - - asm_params = kzalloc(sz, GFP_KERNEL); - if (!asm_params) { - rc = -ENOMEM; - goto fail_cmd1; - } - - q6asm_add_hdr_async(ac, &hdr, sz, TRUE); - atomic_set(&ac->cmd_state_pp, -1); - hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2; - memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr)); - - payload_params.data_payload_addr_lsw = 0; - payload_params.data_payload_addr_msw = 0; - payload_params.mem_map_handle = 0; - payload_params.data_payload_size = - sizeof(struct audproc_chmixer_param_coeff) + - variable_payload + sizeof(struct asm_stream_param_data_v2); - memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), - &payload_params, - sizeof(struct asm_stream_cmd_set_pp_params_v2)); - - data.module_id = AUDPROC_MODULE_ID_MFC; - data.param_id = AUDPROC_CHMIXER_PARAM_ID_COEFF; - data.param_size = sizeof(struct audproc_chmixer_param_coeff) + - variable_payload; - data.reserved = 0; - memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2)), - &data, sizeof(struct asm_stream_param_data_v2)); - - pan_cfg.index = 0; - pan_cfg.num_output_channels = pan_param->num_output_channels; - pan_cfg.num_input_channels = pan_param->num_input_channels; - memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2) + - sizeof(struct asm_stream_param_data_v2)), - &pan_cfg, sizeof(struct audproc_chmixer_param_coeff)); - memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2) + - sizeof(struct asm_stream_param_data_v2) + - sizeof(struct audproc_chmixer_param_coeff)), - pan_param->output_channel_map, - pan_param->num_output_channels * sizeof(uint16_t)); - memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2) + - sizeof(struct asm_stream_param_data_v2) + - sizeof(struct audproc_chmixer_param_coeff) + - pan_param->num_output_channels * sizeof(uint16_t)), - pan_param->input_channel_map, - pan_param->num_input_channels * sizeof(uint16_t)); - - dst_gain_ptr = (uint16_t *) ((u8 *)asm_params + sizeof(struct apr_hdr) + - sizeof(struct asm_stream_cmd_set_pp_params_v2) + - sizeof(struct asm_stream_param_data_v2) + - sizeof(struct audproc_chmixer_param_coeff) + - (pan_param->num_output_channels * sizeof(uint16_t)) + - (pan_param->num_input_channels * sizeof(uint16_t))); - for (ii = 0; ii < pan_param->num_output_channels * - pan_param->num_input_channels; ii++) - dst_gain_ptr[ii] = (uint16_t) pan_param->gain[ii]; - - rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params); - if (rc < 0) { - pr_err("%s: set-params send failed paramid[0x%x] rc %d\n", - __func__, data.param_id, rc); - rc = -EINVAL; - goto fail_cmd2; - } - - rc = wait_event_timeout(ac->cmd_wait, - (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ); - if (!rc) { - pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__, - data.param_id); - rc = -ETIMEDOUT; - goto fail_cmd2; - } - if (atomic_read(&ac->cmd_state_pp) > 0) { - pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n", - __func__, adsp_err_get_err_str( - atomic_read(&ac->cmd_state_pp)), - data.param_id); - rc = adsp_err_get_lnx_err_code( - atomic_read(&ac->cmd_state_pp)); - goto fail_cmd2; - } - rc = 0; -fail_cmd2: - kfree(asm_params); -fail_cmd1: - return rc; -} - int q6asm_equalizer(struct audio_client *ac, void *eq_p) { struct asm_eq_params eq; @@ -7960,7 +7838,6 @@ int q6asm_async_write(struct audio_client *ac, u32 liomode; u32 io_compressed; u32 io_compressed_stream; - int offset = 0; if (ac == NULL) { pr_err("%s: APR handle NULL\n", __func__); @@ -8022,10 +7899,7 @@ int q6asm_async_write(struct audio_client *ac, } } - if (ab != NULL) { - offset = lbuf_phys_addr - ab->phys; - config_debug_fs_write(ab, offset); - } + config_debug_fs_write(ab); rc = apr_send_pkt(ac->apr, (uint32_t *) &write); if (rc < 0) { @@ -8172,7 +8046,7 @@ int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts, write.mem_map_handle); mutex_unlock(&port->lock); - config_debug_fs_write(ab, 0); + config_debug_fs_write(ab); rc = apr_send_pkt(ac->apr, (uint32_t *) &write); if (rc < 0) { diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c index 6fed443186e557a8f6420c1487d60cdb12b74a7c..4340d31c218c1b47a98f8ac7e5247353704bafc5 100644 --- a/sound/soc/msm/qdsp6v2/q6core.c +++ b/sound/soc/msm/qdsp6v2/q6core.c @@ -119,18 +119,6 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv) q6core_lcl.bus_bw_resp_received = 1; wake_up(&q6core_lcl.bus_bw_req_wait); break; - case AVCS_CMD_ADD_POOL_PAGES: - pr_debug("%s: Cmd = AVCS_CMD_ADD_POOL_PAGES status[0x%x]\n", - __func__, payload1[1]); - q6core_lcl.bus_bw_resp_received = 1; - wake_up(&q6core_lcl.bus_bw_req_wait); - break; - case AVCS_CMD_REMOVE_POOL_PAGES: - pr_debug("%s: Cmd = AVCS_CMD_REMOVE_POOL_PAGES status[0x%x]\n", - __func__, payload1[1]); - q6core_lcl.bus_bw_resp_received = 1; - wake_up(&q6core_lcl.bus_bw_req_wait); - break; default: pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n", __func__, @@ -554,56 +542,6 @@ done: return ret; } -int q6core_add_remove_pool_pages(ion_phys_addr_t buf_add, uint32_t bufsz, - uint32_t mempool_id, bool add_pages) -{ - struct avs_mem_assign_region mem_pool; - int ret = 0, sz; - - if (add_pages) - mem_pool.hdr.opcode = AVCS_CMD_ADD_POOL_PAGES; - else - mem_pool.hdr.opcode = AVCS_CMD_REMOVE_POOL_PAGES; - - /* get payload length */ - sz = sizeof(struct avs_mem_assign_region); - mem_pool.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, - APR_HDR_LEN(sizeof(struct apr_hdr)), - APR_PKT_VER); - mem_pool.hdr.src_port = 0; - mem_pool.hdr.dest_port = 0; - mem_pool.hdr.token = 0; - mem_pool.hdr.pkt_size = sz; - mem_pool.pool_id = mempool_id; - mem_pool.size = bufsz; - mem_pool.addr_lsw = lower_32_bits(buf_add); - mem_pool.addr_msw = msm_audio_populate_upper_32_bits(buf_add); - pr_debug("%s: sending memory map, size %d\n", - __func__, bufsz); - - q6core_lcl.bus_bw_resp_received = 0; - ret = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&mem_pool); - if (ret < 0) { - pr_err("%s: library map region failed %d\n", - __func__, ret); - ret = -EINVAL; - goto done; - } - - ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait, - (q6core_lcl.bus_bw_resp_received == 1), - msecs_to_jiffies(TIMEOUT_MS)); - if (!ret) { - pr_err("%s: timeout. waited for library memory map\n", - __func__); - ret = -ETIME; - goto done; - } - ret = 0; -done: - return ret; -} - static int q6core_dereg_all_custom_topologies(void) { int ret = 0; diff --git a/sound/soc/msm/qdsp6v2/sony-hweffect-params.c b/sound/soc/msm/qdsp6v2/sony-hweffect-params.c new file mode 100644 index 0000000000000000000000000000000000000000..4af8c08e62fdd4c7c6796aae3b43a5a481540f81 --- /dev/null +++ b/sound/soc/msm/qdsp6v2/sony-hweffect-params.c @@ -0,0 +1,206 @@ +/* + * Author: Yoshio Yamamoto yoshio.xa.yamamoto@sonymobile.com + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ +/* + * Copyright (C) 2014 Sony Mobile Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include "sound/sony-hweffect-params.h" + + +static struct s_force_tuning_params s_force_coefs; + +static struct clearphase_hp_tuning_params clearphase_hp_coefs; + +static struct clearphase_sp_tuning_params clearphase_sp_coefs; + +static struct xloud_tuning_params xloud_coefs; + +void *sony_hweffect_params_getparam(unsigned int effect_id) +{ + void *hw_params; + + pr_debug("%s: effect id %u\n", __func__, effect_id); + + hw_params = NULL; + + switch (effect_id) { + case SFORCE_PARAM: + hw_params = (void *)&s_force_coefs; + break; + + case CLEARPHASE_HP_PARAM: + hw_params = (void *)&clearphase_hp_coefs; + break; + + case CLEARPHASE_SP_PARAM: + hw_params = (void *)&clearphase_sp_coefs; + break; + + case XLOUD_PARAM: + hw_params = (void *)&xloud_coefs; + break; + + default: + break; + }; + + return hw_params; +} + +static int sony_hweffect_params_open(struct inode *inode, struct file *f) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static long sony_hweffect_params_ioctl_shared(struct file *f, + unsigned int cmd, void __user *arg) +{ + pr_debug("%s %d\n", __func__, cmd); + + switch (cmd) { + case SFORCE_PARAM: + if (copy_from_user(&s_force_coefs, (void *)arg, + sizeof(struct sforce_param_data))) { + pr_err("%s: fail to copy memory handle!\n", __func__); + return -EFAULT; + } + break; + + case CLEARPHASE_HP_PARAM: + if (copy_from_user(&clearphase_hp_coefs, (void *)arg, + sizeof(struct clearphase_hp_param_data))) { + pr_err("%s: fail to copy memory handle!\n", __func__); + return -EFAULT; + } + break; + + case CLEARPHASE_SP_PARAM: + if (copy_from_user(&clearphase_sp_coefs, (void *)arg, + sizeof(struct clearphase_sp_param_data))) { + pr_err("%s: fail to copy memory handle!\n", __func__); + return -EFAULT; + } + break; + + case XLOUD_PARAM: + if (copy_from_user(&xloud_coefs, (void *)arg, + sizeof(struct xloud_param_data))) { + pr_err("%s: fail to copy memory handle!\n", __func__); + return -EFAULT; + } + break; + + default: + return -EFAULT; + }; + return 0; +} + +static long sony_hweffect_params_ioctl(struct file *f, + unsigned int cmd, unsigned long arg) +{ + int result = 0; + + pr_debug("%s %d\n", __func__, cmd); + + result = sony_hweffect_params_ioctl_shared(f, cmd, (void __user *)arg); + + return result; +} + +#ifdef CONFIG_COMPAT +#define SFORCE_PARAM_32 \ + _IOW(SONYEFFECT_HW_PARAMS_IOCTL_MAGIC, 0, compat_uptr_t) +#define CLEARPHASE_HP_PARAM_32 \ + _IOW(SONYEFFECT_HW_PARAMS_IOCTL_MAGIC, 1, compat_uptr_t) +#define CLEARPHASE_SP_PARAM_32 \ + _IOW(SONYEFFECT_HW_PARAMS_IOCTL_MAGIC, 2, compat_uptr_t) +#define XLOUD_PARAM_32 \ + _IOW(SONYEFFECT_HW_PARAMS_IOCTL_MAGIC, 3, compat_uptr_t) + +static long sony_hweffect_params_compat_ioctl(struct file *f, + unsigned int cmd, unsigned long arg) +{ + unsigned int cmd64; + int result = 0; + + switch (cmd) { + case SFORCE_PARAM_32: + cmd64 = SFORCE_PARAM; + break; + case CLEARPHASE_HP_PARAM_32: + cmd64 = CLEARPHASE_HP_PARAM; + break; + case CLEARPHASE_SP_PARAM_32: + cmd64 = CLEARPHASE_SP_PARAM; + break; + case XLOUD_PARAM_32: + cmd64 = XLOUD_PARAM; + break; + default: + result = -EINVAL; + pr_err("%s: Invalid IOCTL, command = %d!\n", + __func__, cmd); + break; + } + + if (!result) + result = sony_hweffect_params_ioctl_shared(f, cmd64, + compat_ptr(arg)); + + return result; +} +#else +#define sony_hweffect_params_compat_ioctl NULL +#endif + +static int sony_hweffect_params_release(struct inode *inode, struct file *f) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static const struct file_operations sony_hweffect_params_fops = { + .owner = THIS_MODULE, + .open = sony_hweffect_params_open, + .release = sony_hweffect_params_release, + .unlocked_ioctl = sony_hweffect_params_ioctl, + .compat_ioctl = sony_hweffect_params_compat_ioctl, +}; + +struct miscdevice sony_hweffect_params_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sony_hweffect_params", + .fops = &sony_hweffect_params_fops, +}; + +static int __init sony_hweffect_params_init(void) +{ + pr_info("%s\n", __func__); + misc_register(&sony_hweffect_params_misc); + return 0; +} + +static void __exit sony_hweffect_params_exit(void) +{ + pr_info("%s\n", __func__); +} + +module_init(sony_hweffect_params_init); +module_exit(sony_hweffect_params_exit); diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c index 30c3ffe2347d4d54b6fca77e524920f42e75ca1a..1c03d8c9e7971c0e634dd3a6b21b1c2c0eed079b 100644 --- a/sound/soc/msm/sdm660-ext-dai-links.c +++ b/sound/soc/msm/sdm660-ext-dai-links.c @@ -1270,10 +1270,10 @@ static struct snd_soc_dai_link msm_ext_common_fe_dai[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, {/* hw:x,33 */ - .name = MSM_DAILINK_NAME(ULL_NOIRQ_2), - .stream_name = "MM_NOIRQ_2", + .name = MSM_DAILINK_NAME(Compress9), + .stream_name = "Compress9", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-pcm-dsp-noirq", + .platform_name = "msm-compress-dsp", .dynamic = 1, .dpcm_capture = 1, .dpcm_playback = 1, diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c index 0f28e100f5356e3c7858e1e728538d4d6385e3ab..f4219148e81cad73be708876f2b2d2912e5bbd3d 100644 --- a/sound/soc/msm/sdm660-internal.c +++ b/sound/soc/msm/sdm660-internal.c @@ -2188,10 +2188,10 @@ static struct snd_soc_dai_link msm_int_dai[] = { .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15, }, {/* hw:x,33 */ - .name = MSM_DAILINK_NAME(ULL_NOIRQ_2), - .stream_name = "MM_NOIRQ_2", + .name = MSM_DAILINK_NAME(Compress9), + .stream_name = "Compress9", .cpu_dai_name = "MultiMedia16", - .platform_name = "msm-pcm-dsp-noirq", + .platform_name = "msm-compress-dsp", .dynamic = 1, .dpcm_capture = 1, .dpcm_playback = 1, diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index 8a679b21f0c4b764f848fab12590c09844ed1b05..fa7208a32d763d0ae35e953ccff82c69c772a5c2 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -115,13 +115,4 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s #define WRITE_ONCE(x, val) \ ({ union { typeof(x) __val; char __c[1]; } __u = { .__val = (val) }; __write_once_size(&(x), __u.__c, sizeof(x)); __u.__val; }) - -#ifndef __fallthrough -# if defined(__GNUC__) && __GNUC__ >= 7 -# define __fallthrough __attribute__ ((fallthrough)) -# else -# define __fallthrough -# endif -#endif - #endif /* _TOOLS_LINUX_COMPILER_H */ diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h index e69118b2077e63d091754e24fcc8e6bf7aa488c6..c808c7d02d21c86732c2aab981ccebd0dad71aad 100644 --- a/tools/lib/lockdep/uinclude/linux/lockdep.h +++ b/tools/lib/lockdep/uinclude/linux/lockdep.h @@ -8,7 +8,7 @@ #include #include -#define MAX_LOCK_DEPTH 255UL +#define MAX_LOCK_DEPTH 2000UL #define asmlinkage #define __visible diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c index fa5d17af88b7365174bf49ccb0c214fc5880c559..d28c1b6a3b54d3d6cd89e14b4d1770168fcf3d8b 100644 --- a/tools/perf/arch/x86/tests/intel-cqm.c +++ b/tools/perf/arch/x86/tests/intel-cqm.c @@ -17,7 +17,7 @@ static pid_t spawn(void) if (pid) return pid; - while(1) + while(1); sleep(5); return 0; } diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c index 1f86ee8fb831c99e8d22ead64ca33ec11a816985..9223c164e545d869267b9b7a17d409b774dd7904 100644 --- a/tools/perf/arch/x86/util/dwarf-regs.c +++ b/tools/perf/arch/x86/util/dwarf-regs.c @@ -63,8 +63,6 @@ struct pt_regs_offset { # define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} #endif -/* TODO: switching by dwarf address size */ -#ifndef __x86_64__ static const struct pt_regs_offset x86_32_regoffset_table[] = { REG_OFFSET_NAME_32("%ax", eax), REG_OFFSET_NAME_32("%cx", ecx), @@ -77,8 +75,6 @@ static const struct pt_regs_offset x86_32_regoffset_table[] = { REG_OFFSET_END, }; -#define regoffset_table x86_32_regoffset_table -#else static const struct pt_regs_offset x86_64_regoffset_table[] = { REG_OFFSET_NAME_64("%ax", rax), REG_OFFSET_NAME_64("%dx", rdx), @@ -99,7 +95,11 @@ static const struct pt_regs_offset x86_64_regoffset_table[] = { REG_OFFSET_END, }; +/* TODO: switching by dwarf address size */ +#ifdef __x86_64__ #define regoffset_table x86_64_regoffset_table +#else +#define regoffset_table x86_32_regoffset_table #endif /* Minus 1 for the ending REG_OFFSET_END */ diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index b4eb5b6790810b139efb669e6a86a63ca6ce85b2..492df2752a2d1057bbde642538f84da93aa9df8b 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -1570,13 +1570,13 @@ static int __bench_numa(const char *name) "GB/sec,", "total-speed", "GB/sec total speed"); if (g->p.show_details >= 2) { - char tname[14 + 2 * 10 + 1]; + char tname[32]; struct thread_data *td; for (p = 0; p < g->p.nr_proc; p++) { for (t = 0; t < g->p.nr_threads; t++) { - memset(tname, 0, sizeof(tname)); + memset(tname, 0, 32); td = g->threads + p*g->p.nr_threads + t; - snprintf(tname, sizeof(tname), "process%d:thread%d", p, t); + snprintf(tname, 32, "process%d:thread%d", p, t); print_res(tname, td->speed_gbs, "GB/sec", "thread-speed", "GB/sec/thread speed"); print_res(tname, td->system_time_ns / 1e9, diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 48840556bf2de8ecca40d1f3c26da7b59c3ee721..368d1e1561f749644105d19dcf2b8d1989860b9c 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1253,19 +1253,21 @@ static int is_directory(const char *base_path, const struct dirent *dent) return S_ISDIR(st.st_mode); } -#define for_each_lang(scripts_path, scripts_dir, lang_dirent) \ - while ((lang_dirent = readdir(scripts_dir)) != NULL) \ - if ((lang_dirent->d_type == DT_DIR || \ - (lang_dirent->d_type == DT_UNKNOWN && \ - is_directory(scripts_path, lang_dirent))) && \ - (strcmp(lang_dirent->d_name, ".")) && \ - (strcmp(lang_dirent->d_name, ".."))) - -#define for_each_script(lang_path, lang_dir, script_dirent) \ - while ((script_dirent = readdir(lang_dir)) != NULL) \ - if (script_dirent->d_type != DT_DIR && \ - (script_dirent->d_type != DT_UNKNOWN || \ - !is_directory(lang_path, script_dirent))) +#define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\ + while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ + lang_next) \ + if ((lang_dirent.d_type == DT_DIR || \ + (lang_dirent.d_type == DT_UNKNOWN && \ + is_directory(scripts_path, &lang_dirent))) && \ + (strcmp(lang_dirent.d_name, ".")) && \ + (strcmp(lang_dirent.d_name, ".."))) + +#define for_each_script(lang_path, lang_dir, script_dirent, script_next)\ + while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ + script_next) \ + if (script_dirent.d_type != DT_DIR && \ + (script_dirent.d_type != DT_UNKNOWN || \ + !is_directory(lang_path, &script_dirent))) #define RECORD_SUFFIX "-record" @@ -1411,7 +1413,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused, const char *s __maybe_unused, int unset __maybe_unused) { - struct dirent *script_dirent, *lang_dirent; + struct dirent *script_next, *lang_next, script_dirent, lang_dirent; char scripts_path[MAXPATHLEN]; DIR *scripts_dir, *lang_dir; char script_path[MAXPATHLEN]; @@ -1426,19 +1428,19 @@ static int list_available_scripts(const struct option *opt __maybe_unused, if (!scripts_dir) return -1; - for_each_lang(scripts_path, scripts_dir, lang_dirent) { + for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, - lang_dirent->d_name); + lang_dirent.d_name); lang_dir = opendir(lang_path); if (!lang_dir) continue; - for_each_script(lang_path, lang_dir, script_dirent) { - script_root = get_script_root(script_dirent, REPORT_SUFFIX); + for_each_script(lang_path, lang_dir, script_dirent, script_next) { + script_root = get_script_root(&script_dirent, REPORT_SUFFIX); if (script_root) { desc = script_desc__findnew(script_root); snprintf(script_path, MAXPATHLEN, "%s/%s", - lang_path, script_dirent->d_name); + lang_path, script_dirent.d_name); read_script_info(desc, script_path); free(script_root); } @@ -1526,7 +1528,7 @@ static int check_ev_match(char *dir_name, char *scriptname, */ int find_scripts(char **scripts_array, char **scripts_path_array) { - struct dirent *script_dirent, *lang_dirent; + struct dirent *script_next, *lang_next, script_dirent, lang_dirent; char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; DIR *scripts_dir, *lang_dir; struct perf_session *session; @@ -1549,9 +1551,9 @@ int find_scripts(char **scripts_array, char **scripts_path_array) return -1; } - for_each_lang(scripts_path, scripts_dir, lang_dirent) { + for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path, - lang_dirent->d_name); + lang_dirent.d_name); #ifdef NO_LIBPERL if (strstr(lang_path, "perl")) continue; @@ -1565,16 +1567,16 @@ int find_scripts(char **scripts_array, char **scripts_path_array) if (!lang_dir) continue; - for_each_script(lang_path, lang_dir, script_dirent) { + for_each_script(lang_path, lang_dir, script_dirent, script_next) { /* Skip those real time scripts: xxxtop.p[yl] */ - if (strstr(script_dirent->d_name, "top.")) + if (strstr(script_dirent.d_name, "top.")) continue; sprintf(scripts_path_array[i], "%s/%s", lang_path, - script_dirent->d_name); - temp = strchr(script_dirent->d_name, '.'); + script_dirent.d_name); + temp = strchr(script_dirent.d_name, '.'); snprintf(scripts_array[i], - (temp - script_dirent->d_name) + 1, - "%s", script_dirent->d_name); + (temp - script_dirent.d_name) + 1, + "%s", script_dirent.d_name); if (check_ev_match(lang_path, scripts_array[i], session)) @@ -1592,7 +1594,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array) static char *get_script_path(const char *script_root, const char *suffix) { - struct dirent *script_dirent, *lang_dirent; + struct dirent *script_next, *lang_next, script_dirent, lang_dirent; char scripts_path[MAXPATHLEN]; char script_path[MAXPATHLEN]; DIR *scripts_dir, *lang_dir; @@ -1605,21 +1607,21 @@ static char *get_script_path(const char *script_root, const char *suffix) if (!scripts_dir) return NULL; - for_each_lang(scripts_path, scripts_dir, lang_dirent) { + for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, - lang_dirent->d_name); + lang_dirent.d_name); lang_dir = opendir(lang_path); if (!lang_dir) continue; - for_each_script(lang_path, lang_dir, script_dirent) { - __script_root = get_script_root(script_dirent, suffix); + for_each_script(lang_path, lang_dir, script_dirent, script_next) { + __script_root = get_script_root(&script_dirent, suffix); if (__script_root && !strcmp(script_root, __script_root)) { free(__script_root); closedir(lang_dir); closedir(scripts_dir); snprintf(script_path, MAXPATHLEN, "%s/%s", - lang_path, script_dirent->d_name); + lang_path, script_dirent.d_name); return strdup(script_path); } free(__script_root); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4a8a02c302d237871ee4253edae86dc923527f3b..7e2e72e6d9d16323c3c448986372fa13234d368a 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -636,7 +636,7 @@ repeat: case -1: if (errno == EINTR) continue; - __fallthrough; + /* Fall trhu */ default: c = getc(stdin); tcsetattr(0, TCSAFLUSH, &save); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index ebe7115c751aa66fb589bd4b1342fbe9080b094f..c783d8fd3a80fb4ae29ab2cb81d3a7d8b54a0123 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1617,7 +1617,6 @@ static int trace__process_event(struct trace *trace, struct machine *machine, color_fprintf(trace->output, PERF_COLOR_RED, "LOST %" PRIu64 " events!\n", event->lost.lost); ret = machine__process_lost_event(machine, event, sample); - break; default: ret = machine__process_event(machine, event, sample); break; diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 54af2f2e2ee4f6b724249a466e88bc1599881cf1..636d7b42d8447f93917ce64b0aff528fd3fceed6 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1727,14 +1727,15 @@ static int test_pmu_events(void) } while (!ret && (ent = readdir(dir))) { +#define MAX_NAME 100 struct evlist_test e; - char name[2 * NAME_MAX + 1 + 12 + 3]; + char name[MAX_NAME]; if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; - snprintf(name, sizeof(name), "cpu/event=%s/u", ent->d_name); + snprintf(name, MAX_NAME, "cpu/event=%s/u", ent->d_name); e.name = name; e.check = test__checkevent_pmu_events; @@ -1742,10 +1743,11 @@ static int test_pmu_events(void) ret = test_event(&e); if (ret) break; - snprintf(name, sizeof(name), "%s:u,cpu/event=%s/u", ent->d_name, ent->d_name); + snprintf(name, MAX_NAME, "%s:u,cpu/event=%s/u", ent->d_name, ent->d_name); e.name = name; e.check = test__checkevent_pmu_events_mix; ret = test_event(&e); +#undef MAX_NAME } closedir(dir); diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 718bd46d47fa7bc88674a192dd1a8e8ab1fb7ca9..d4d7cc27252f1184bf2d678b6460f138099efd28 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -755,11 +755,11 @@ static int annotate_browser__run(struct annotate_browser *browser, nd = browser->curr_hot; break; case K_UNTAB: - if (nd != NULL) { + if (nd != NULL) nd = rb_next(nd); if (nd == NULL) nd = rb_first(&browser->entries); - } else + else nd = browser->curr_hot; break; case K_F1: diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 26cba64345e3654823ba3e72e6df4a7a60846960..956187bf1a8532454dec1c2aa8fa4c4a9a827928 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -416,7 +416,7 @@ static int __event__synthesize_thread(union perf_event *comm_event, { char filename[PATH_MAX]; DIR *tasks; - struct dirent *dirent; + struct dirent dirent, *next; pid_t tgid, ppid; int rc = 0; @@ -445,11 +445,11 @@ static int __event__synthesize_thread(union perf_event *comm_event, return 0; } - while ((dirent = readdir(tasks)) != NULL) { + while (!readdir_r(tasks, &dirent, &next) && next) { char *end; pid_t _pid; - _pid = strtol(dirent->d_name, &end, 10); + _pid = strtol(dirent.d_name, &end, 10); if (*end) continue; @@ -558,7 +558,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, { DIR *proc; char proc_path[PATH_MAX]; - struct dirent *dirent; + struct dirent dirent, *next; union perf_event *comm_event, *mmap_event, *fork_event; int err = -1; @@ -583,9 +583,9 @@ int perf_event__synthesize_threads(struct perf_tool *tool, if (proc == NULL) goto out_free_fork; - while ((dirent = readdir(proc)) != NULL) { + while (!readdir_r(proc, &dirent, &next) && next) { char *end; - pid_t pid = strtol(dirent->d_name, &end, 10); + pid_t pid = strtol(dirent.d_name, &end, 10); if (*end) /* only interested in proper numerical dirents */ continue; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 933a509a90f89f7cf84422b475b02e5101307a6d..71df7acf86435bd000567b9a00acec9562b7e417 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -22,7 +22,6 @@ #include #include #include -#include #include "../cache.h" #include "../util.h" @@ -1709,7 +1708,6 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder) switch (decoder->packet.type) { case INTEL_PT_TIP_PGD: decoder->continuous_period = false; - __fallthrough; case INTEL_PT_TIP_PGE: case INTEL_PT_TIP: intel_pt_log("ERROR: Unexpected packet\n"); @@ -1764,8 +1762,6 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder) decoder->pge = false; decoder->continuous_period = false; intel_pt_clear_tx_flags(decoder); - __fallthrough; - case INTEL_PT_TNT: decoder->have_tma = false; intel_pt_log("ERROR: Unexpected packet\n"); @@ -1806,7 +1802,6 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) switch (decoder->packet.type) { case INTEL_PT_TIP_PGD: decoder->continuous_period = false; - __fallthrough; case INTEL_PT_TIP_PGE: case INTEL_PT_TIP: decoder->pge = decoder->packet.type != INTEL_PT_TIP_PGD; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index 9b2fce25162b4e19e504c6fc225102d055616cfd..b1257c816310fefe0bed0e963fc106273c019da1 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "intel-pt-pkt-decoder.h" @@ -489,7 +488,6 @@ int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf, case INTEL_PT_FUP: if (!(packet->count)) return snprintf(buf, buf_len, "%s no ip", name); - __fallthrough; case INTEL_PT_CYC: case INTEL_PT_VMCS: case INTEL_PT_MTC: diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 881bbb5e79125e2150830d9e9e565217edc8e683..854dd2105bd584786caec47344acf0636b0d990c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -138,11 +138,11 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) -#define for_each_subsystem(sys_dir, sys_dirent) \ - while ((sys_dirent = readdir(sys_dir)) != NULL) \ - if (sys_dirent->d_type == DT_DIR && \ - (strcmp(sys_dirent->d_name, ".")) && \ - (strcmp(sys_dirent->d_name, ".."))) +#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ + while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ + if (sys_dirent.d_type == DT_DIR && \ + (strcmp(sys_dirent.d_name, ".")) && \ + (strcmp(sys_dirent.d_name, ".."))) static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) { @@ -159,12 +159,12 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) return 0; } -#define for_each_event(sys_dirent, evt_dir, evt_dirent) \ - while ((evt_dirent = readdir(evt_dir)) != NULL) \ - if (evt_dirent->d_type == DT_DIR && \ - (strcmp(evt_dirent->d_name, ".")) && \ - (strcmp(evt_dirent->d_name, "..")) && \ - (!tp_event_has_id(sys_dirent, evt_dirent))) +#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \ + while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ + if (evt_dirent.d_type == DT_DIR && \ + (strcmp(evt_dirent.d_name, ".")) && \ + (strcmp(evt_dirent.d_name, "..")) && \ + (!tp_event_has_id(&sys_dirent, &evt_dirent))) #define MAX_EVENT_LENGTH 512 @@ -173,7 +173,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) { struct tracepoint_path *path = NULL; DIR *sys_dir, *evt_dir; - struct dirent *sys_dirent, *evt_dirent; + struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; char id_buf[24]; int fd; u64 id; @@ -184,18 +184,18 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) if (!sys_dir) return NULL; - for_each_subsystem(sys_dir, sys_dirent) { + for_each_subsystem(sys_dir, sys_dirent, sys_next) { snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, - sys_dirent->d_name); + sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) continue; - for_each_event(sys_dirent, evt_dir, evt_dirent) { + for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, - evt_dirent->d_name); + evt_dirent.d_name); fd = open(evt_path, O_RDONLY); if (fd < 0) continue; @@ -220,9 +220,9 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) free(path); return NULL; } - strncpy(path->system, sys_dirent->d_name, + strncpy(path->system, sys_dirent.d_name, MAX_EVENT_LENGTH); - strncpy(path->name, evt_dirent->d_name, + strncpy(path->name, evt_dirent.d_name, MAX_EVENT_LENGTH); return path; } @@ -1662,7 +1662,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, bool name_only) { DIR *sys_dir, *evt_dir; - struct dirent *sys_dirent, *evt_dirent; + struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; char **evt_list = NULL; @@ -1680,20 +1680,20 @@ restart: goto out_close_sys_dir; } - for_each_subsystem(sys_dir, sys_dirent) { + for_each_subsystem(sys_dir, sys_dirent, sys_next) { if (subsys_glob != NULL && - !strglobmatch(sys_dirent->d_name, subsys_glob)) + !strglobmatch(sys_dirent.d_name, subsys_glob)) continue; snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, - sys_dirent->d_name); + sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) continue; - for_each_event(sys_dirent, evt_dir, evt_dirent) { + for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { if (event_glob != NULL && - !strglobmatch(evt_dirent->d_name, event_glob)) + !strglobmatch(evt_dirent.d_name, event_glob)) continue; if (!evt_num_known) { @@ -1702,7 +1702,7 @@ restart: } snprintf(evt_path, MAXPATHLEN, "%s:%s", - sys_dirent->d_name, evt_dirent->d_name); + sys_dirent.d_name, evt_dirent.d_name); evt_list[evt_i] = strdup(evt_path); if (evt_list[evt_i] == NULL) @@ -1755,7 +1755,7 @@ out_close_sys_dir: int is_valid_tracepoint(const char *event_string) { DIR *sys_dir, *evt_dir; - struct dirent *sys_dirent, *evt_dirent; + struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; @@ -1763,17 +1763,17 @@ int is_valid_tracepoint(const char *event_string) if (!sys_dir) return 0; - for_each_subsystem(sys_dir, sys_dirent) { + for_each_subsystem(sys_dir, sys_dirent, sys_next) { snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, - sys_dirent->d_name); + sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) continue; - for_each_event(sys_dirent, evt_dir, evt_dirent) { + for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { snprintf(evt_path, MAXPATHLEN, "%s:%s", - sys_dirent->d_name, evt_dirent->d_name); + sys_dirent.d_name, evt_dirent.d_name); if (!strcmp(evt_path, event_string)) { closedir(evt_dir); closedir(sys_dir); diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 593066c68e3da37a1f49ec12b021faf46fe11923..6f2a0279476c1a98c2f44fafc3e3fcbfc9ef4bcb 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -153,7 +153,7 @@ static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *n if (fd == -1) return -1; - sret = read(fd, alias->unit, UNIT_MAX_LEN); + sret = read(fd, alias->unit, UNIT_MAX_LEN); if (sret < 0) goto error; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index fdd87c7e3e9172a5f004d31a61aa97c371e6a4e4..05012bb178d7a8d75ebf4879438fbc0d6f774926 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -1460,12 +1460,16 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, Dwarf_Addr _addr = 0, baseaddr = 0; const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; int baseline = 0, lineno = 0, ret = 0; + bool reloc = false; - /* We always need to relocate the address for aranges */ - if (debuginfo__get_text_offset(dbg, &baseaddr) == 0) - addr += baseaddr; +retry: /* Find cu die */ if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { + if (!reloc && debuginfo__get_text_offset(dbg, &baseaddr) == 0) { + addr += baseaddr; + reloc = true; + goto retry; + } pr_warning("Failed to find debug information for address %lx\n", addr); ret = -EINVAL; diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build index 82d28c67e0f3b7630d939e0a71fdad80a1be6dbd..6516e220c24752fe729b17ddaf94115d6795f90a 100644 --- a/tools/perf/util/scripting-engines/Build +++ b/tools/perf/util/scripting-engines/Build @@ -1,6 +1,6 @@ libperf-$(CONFIG_LIBPERL) += trace-event-perl.o libperf-$(CONFIG_LIBPYTHON) += trace-event-python.o -CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-nested-externs -Wno-undef -Wno-switch-default +CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c index efb53772e0ecc8e6a9c9ea4493d37c6dc55d38bf..bcae659b65462cddff5c03c2c41a8fc675ad05bc 100644 --- a/tools/perf/util/strfilter.c +++ b/tools/perf/util/strfilter.c @@ -269,7 +269,6 @@ static int strfilter_node__sprint(struct strfilter_node *node, char *buf) len = strfilter_node__sprint_pt(node->l, buf); if (len < 0) return len; - __fallthrough; case '!': if (buf) { *(buf + len++) = *node->p; diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index accb7ece1d3cbf1d00b08adc9c6f3dc1b96d7a53..fc8781de62dbbed618e1f220225dfaeb195ef7f0 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c @@ -21,8 +21,6 @@ s64 perf_atoll(const char *str) case 'b': case 'B': if (*p) goto out_err; - - __fallthrough; case '\0': return length; default: diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 829508a214481d9e8ba1a0d4337e52c571d47bc1..0a9ae8014729c085ffd2872e2bc13871f79c9908 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -227,7 +227,7 @@ void thread__find_cpumode_addr_location(struct thread *thread, struct addr_location *al) { size_t i; - const u8 cpumodes[] = { + const u8 const cpumodes[] = { PERF_RECORD_MISC_USER, PERF_RECORD_MISC_KERNEL, PERF_RECORD_MISC_GUEST_USER, diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 4e666b95b87e86c2ca700bc7a1dd49e87d754499..6ec3c5ca438f25c827dcfc1b7bde3491f8a5fe8c 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -92,8 +92,8 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) { DIR *proc; int max_threads = 32, items, i; - char path[NAME_MAX + 1 + 6]; - struct dirent *dirent, **namelist = NULL; + char path[256]; + struct dirent dirent, *next, **namelist = NULL; struct thread_map *threads = thread_map__alloc(max_threads); if (threads == NULL) @@ -106,16 +106,16 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) threads->nr = 0; atomic_set(&threads->refcnt, 1); - while ((dirent = readdir(proc)) != NULL) { + while (!readdir_r(proc, &dirent, &next) && next) { char *end; bool grow = false; struct stat st; - pid_t pid = strtol(dirent->d_name, &end, 10); + pid_t pid = strtol(dirent.d_name, &end, 10); if (*end) /* only interested in proper numerical dirents */ continue; - snprintf(path, sizeof(path), "/proc/%s", dirent->d_name); + snprintf(path, sizeof(path), "/proc/%s", dirent.d_name); if (stat(path, &st) != 0) continue; diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index 5a6016224bb9c9c4bbe5f7b28c37738f0edec5a3..719311b5e873ce3cc05b13e09b270008758425a1 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -18,6 +18,11 @@ * * Authors: Wu Fengguang */ +/* + * NOTE: This file has been modified by Sony Mobile Communications Inc. + * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, + * and licensed under the license of the file. + */ #define _FILE_OFFSET_BITS 64 #define _GNU_SOURCE diff --git a/tools/vm/page_owner_sort.c b/tools/vm/page_owner_sort.c index f1c055f3c2436564302adebf429f239557d14a3c..77147b42d598be985abd087e5eb8ea5ea95875fc 100644 --- a/tools/vm/page_owner_sort.c +++ b/tools/vm/page_owner_sort.c @@ -79,12 +79,12 @@ static void add_list(char *buf, int len) } } -#define BUF_SIZE (128 * 1024) +#define BUF_SIZE 1024 int main(int argc, char **argv) { FILE *fin, *fout; - char *buf; + char buf[BUF_SIZE]; int ret, i, count; struct block_list *list2; struct stat st; @@ -107,11 +107,6 @@ int main(int argc, char **argv) max_size = st.st_size / 100; /* hack ... */ list = malloc(max_size * sizeof(*list)); - buf = malloc(BUF_SIZE); - if (!list || !buf) { - printf("Out of memory\n"); - exit(1); - } for ( ; ; ) { ret = read_block(buf, BUF_SIZE, fin);